home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Environments
/
PowerLisp 2.01
/
Supplemental Documentation
/
Documentation
/
Chapter 28. CLOS
< prev
next >
Wrap
Text File
|
1996-05-27
|
231KB
|
5,001 lines
Common Lisp the Language, 2nd Edition
-------------------------------------------------------------------------------
28. Common Lisp Object System
By Daniel G. Bobrow, Linda G. DeMichiel, Richard P. Gabriel, Sonya E. Keene,
Gregor Kiczales, and David A. Moon
[change_begin]
PREFACE: X3J13 voted in June 1988 (CLOS) to adopt the first two chapters (of
three) of the Common Lisp Object System specification as a part of the
forthcoming draft Common Lisp standard.
This chapter presents the bulk of the first two chapters of the Common Lisp
Object System specification; it is substantially identical to these two
specification chapters as previously published elsewhere [5,6,7]. I have edited
the material only very lightly to conform to the overall style of this book and
to save a substantial number of pages by using a typographically condensed
presentation. I have inserted a small number of bracketed remarks, identified
by the initials GLS. The chapter divisions of the original specification have
become section divisions in this chapter; references to the three chapters of
the original specification now refer to the three ``parts'' of the
specification. (See the Acknowledgments to this second edition for
acknowledgments to others who contributed to the Common Lisp Object System
specification.) This is not the last word on CLOS; X3J13 may well refine this
material further. Keene has written a good tutorial introduction to CLOS [26].
- Guy L. Steele Jr.
[change_end]
-------------------------------------------------------------------------------
* Programmer Interface Concepts
o Error Terminology
o Classes
+ Defining Classes
+ Creating Instances of Classes
+ Slots
+ Accessing Slots
o Inheritance
+ Inheritance of Methods
+ Inheritance of Slots and Slot Options
+ Inheritance of Class Options
+ Examples
o Integrating Types and Classes
o Determining the Class Precedence List
+ Topological Sorting
+ Examples
o Generic Functions and Methods
+ Introduction to Generic Functions
+ Introduction to Methods
+ Agreement on Parameter Specializers and Qualifiers
+ Congruent Lambda-Lists for All Methods of a Generic Function
+ Keyword Arguments in Generic Functions and Methods
o Method Selection and Combination
+ Determining the Effective Method
+ Standard Method Combination
+ Declarative Method Combination
+ Built-in Method Combination Types
o Meta-objects
+ Metaclasses
+ Standard Metaclasses
+ Standard Meta-objects
o Object Creation and Initialization
+ Initialization Arguments
+ Declaring the Validity of Initialization Arguments
+ Defaulting of Initialization Arguments
+ Rules for Initialization Arguments
+ Shared-Initialize
+ Initialize-Instance
+ Definitions of Make-Instance and Initialize-Instance
o Redefining Classes
+ Modifying the Structure of Instances
+ Initializing Newly Added Local Slots
+ Customizing Class Redefinition
+ Extensions
o Changing the Class of an Instance
+ Modifying the Structure of an Instance
+ Initializing Newly Added Local Slots
+ Customizing the Change of Class of an Instance
o Reinitializing an Instance
+ Customizing Reinitialization
* Functions in the Programmer Interface
-------------------------------------------------------------------------------
28.1. Programmer Interface Concepts
[change_begin]
The Common Lisp Object System (CLOS) is an object-oriented extension to Common
Lisp. It is based on generic functions, multiple inheritance, declarative
method combination, and a meta-object protocol.
The first two parts of this specification describe the standard Programmer
Interface for the Common Lisp Object System. The first part, Programmer
Interface Concepts, contains a description of the concepts of the Common Lisp
Object System, and the second part, Functions in the Programmer Interface,
contains a description of the functions and macros in the Common Lisp Object
System Programmer Interface. The third part, The Common Lisp Object System
Meta-Object Protocol, explains how the Common Lisp Object System can be
customized. [The third part has not yet been approved by X3J13 for inclusion in
the forthcoming Common Lisp standard and is not included in this book.-GLS]
The fundamental objects of the Common Lisp Object System are classes,
instances, generic functions, and methods.
A class object determines the structure and behavior of a set of other objects,
which are called its instances. Every Common Lisp object is an instance of a
class. The class of an object determines the set of operations that can be
performed on the object.
A generic function is a function whose behavior depends on the classes or
identities of the arguments supplied to it. A generic function object contains
a set of methods, a lambda-list, a method combination type, and other
information. The methods define the class-specific behavior and operations of
the generic function; a method is said to specialize a generic function. When
invoked, a generic function executes a subset of its methods based on the
classes of its arguments.
A generic function can be used in the same ways as an ordinary function in
Common Lisp; in particular, a generic function can be used as an argument to
funcall and apply and can be given a global or a local name.
A method is an object that contains a method function, a sequence of parameter
specializers that specify when the given method is applicable, and a sequence
of qualifiers that is used by the method combination facility to distinguish
among methods. Each required formal parameter of each method has an associated
parameter specializer, and the method will be invoked only on arguments that
satisfy its parameter specializers.
The method combination facility controls the selection of methods, the order in
which they are run, and the values that are returned by the generic function.
The Common Lisp Object System offers a default method combination type and
provides a facility for declaring new types of method combination.
[change_end]
-------------------------------------------------------------------------------
* Error Terminology
* Classes
o Defining Classes
o Creating Instances of Classes
o Slots
o Accessing Slots
* Inheritance
o Inheritance of Methods
o Inheritance of Slots and Slot Options
o Inheritance of Class Options
o Examples
* Integrating Types and Classes
* Determining the Class Precedence List
o Topological Sorting
o Examples
* Generic Functions and Methods
o Introduction to Generic Functions
o Introduction to Methods
o Agreement on Parameter Specializers and Qualifiers
o Congruent Lambda-Lists for All Methods of a Generic Function
o Keyword Arguments in Generic Functions and Methods
* Method Selection and Combination
o Determining the Effective Method
o Standard Method Combination
o Declarative Method Combination
o Built-in Method Combination Types
* Meta-objects
o Metaclasses
o Standard Metaclasses
o Standard Meta-objects
* Object Creation and Initialization
o Initialization Arguments
o Declaring the Validity of Initialization Arguments
o Defaulting of Initialization Arguments
o Rules for Initialization Arguments
o Shared-Initialize
o Initialize-Instance
o Definitions of Make-Instance and Initialize-Instance
* Redefining Classes
o Modifying the Structure of Instances
o Initializing Newly Added Local Slots
o Customizing Class Redefinition
o Extensions
* Changing the Class of an Instance
o Modifying the Structure of an Instance
o Initializing Newly Added Local Slots
o Customizing the Change of Class of an Instance
* Reinitializing an Instance
o Customizing Reinitialization
-------------------------------------------------------------------------------
28.1.1. Error Terminology
[change_begin]
The terminology used in this chapter to describe erroneous situations differs
from the terminology used in the first edition. The new terminology involves
situations; a situation is the evaluation of an expression in some specific
context. For example, a situation might be the invocation of a function on
arguments that fail to satisfy some specified constraints.
In the specification of the Common Lisp Object System, the behavior of programs
in all situations is described, and the options available to the implementor
are defined. No implementation is allowed to extend the syntax or semantics of
the Object System except as explicitly defined in the Object System
specification. In particular, no implementation is allowed to extend the syntax
of the Object System in such a way that ambiguity between the specified syntax
of the Object System and those extensions is possible.
``When situation S occurs, an error is signaled.''
This terminology has the following meaning:
o If this situation occurs, an error will be signaled in the
interpreter and in code compiled under all compiler safety
optimization levels.
o Valid programs may rely on the fact that an error will be signaled
in the interpreter and in code compiled under all compiler safety
optimization levels.
o Every implementation is required to detect such an error in the
interpreter and in code compiled under all compiler safety
optimization levels.
``When situation S occurs, an error should be signaled.''
This terminology has the following meaning:
o If this situation occurs, an error will be signaled at least in the
interpreter and in code compiled under the safest compiler safety
optimization level.
o Valid programs may not rely on the fact that an error will be
signaled.
o Every implementation is required to detect such an error at least in
the interpreter and in code compiled under the safest compiler safety
optimization level.
o When an error is not signaled, the results are undefined (see
below).
``When situation S occurs, the results are undefined.''
This terminology has the following meaning:
o If this situation occurs, the results are unpredictable. The results
may range from harmless to fatal.
o Implementations are allowed to detect this situation and signal an
error, but no implementation is required to detect the situation.
o No valid program may depend on the effects of this situation, and
all valid programs are required to treat the effects of this
situation as unpredictable.
``When situation S occurs, the results are unspecified.''
This terminology has the following meaning:
o The effects of this situation are not specified in the Object
System, but the effects are harmless.
o Implementations are allowed to specify the effects of this
situation.
o No portable program can depend on the effects of this situation, and
all portable programs are required to treat the situation as
unpredictable but harmless.
``The Common Lisp Object System may be extended to cover situation S.''
The meaning of this terminology is that an implementation is free to treat
situation S in one of three ways:
o When situation S occurs, an error is signaled at least in the
interpreter and in code compiled under the safest compiler safety
optimization level.
o When situation S occurs, the results are undefined.
o When situation S occurs, the results are defined and specified.
In addition, this terminology has the following meaning:
o No portable program can depend on the effects of this situation, and
all portable programs are required to treat the situation as
undefined.
``Implementations are free to extend the syntax S.''
This terminology has the following meaning:
o Implementations are allowed to define unambiguous extensions to
syntax S.
o No portable program can depend on this extension, and all portable
programs are required to treat the syntax as meaningless.
The Common Lisp Object System specification may disallow certain extensions
while allowing others.
[change_end]
-------------------------------------------------------------------------------
28.1.2. Classes
[change_begin]
A class is an object that determines the structure and behavior of a set of
other objects, which are called its instances.
A class can inherit structure and behavior from other classes. A class whose
definition refers to other classes for the purpose of inheriting from them is
said to be a subclass of each of those classes. The classes that are designated
for purposes of inheritance are said to be superclasses of the inheriting
class.
A class can have a name. The function class-name takes a class object and
returns its name. The name of an anonymous class is nil. A symbol can name a
class. The function find-class takes a symbol and returns the class that the
symbol names. A class has a proper name if the name is a symbol and if the name
of the class names that class. That is, a class C has the proper name S if S =
(class-name C) and C = (find-class S). Notice that it is possible for
(find-class ) = (find-class ) and . If C = (find-class S), we say that C
is the class named S.
A class is a direct superclass of a class if explicitly designates
as a superclass in its definition. In this case, is a direct subclass of .
A class is a superclass of a class if there exists a series of classes
such that is a direct superclass of for 1 i < n. In this case, is a
subclass of . A class is considered neither a superclass nor a subclass of
itself. That is, if is a superclass of , then . The set of classes
consisting of some given class C along with all of its superclasses is called
``C and its superclasses.''
Each class has a class precedence list, which is a total ordering on the set of
the given class and its superclasses. The total ordering is expressed as a list
ordered from most specific to least specific. The class precedence list is used
in several ways. In general, more specific classes can shadow, or override,
features that would otherwise be inherited from less specific classes. The
method selection and combination process uses the class precedence list to
order methods from most specific to least specific.
When a class is defined, the order in which its direct superclasses are
mentioned in the defining form is important. Each class has a local precedence
order, which is a list consisting of the class followed by its direct
superclasses in the order mentioned in the defining form.
A class precedence list is always consistent with the local precedence order of
each class in the list. The classes in each local precedence order appear
within the class precedence list in the same order. If the local precedence
orders are inconsistent with each other, no class precedence list can be
constructed, and an error is signaled. The class precedence list and its
computation is discussed in section 28.1.5.
Classes are organized into a directed acyclic graph. There are two
distinguished classes, named t and standard-object. The class named t has no
superclasses. It is a superclass of every class except itself. The class named
standard-object is an instance of the class standard-class and is a superclass
of every class that is an instance of standard-class except itself.
There is a mapping from the Common Lisp Object System class space into the
Common Lisp type space. Many of the standard Common Lisp types have a
corresponding class that has the same name as the type. Some Common Lisp types
do not have a corresponding class. The integration of the type and class
systems is discussed in section 28.1.4.
Classes are represented by objects that are themselves instances of classes.
The class of the class of an object is termed the metaclass of that object.
When no misinterpretation is possible, the term metaclass will be used to refer
to a class that has instances that are themselves classes. The metaclass
determines the form of inheritance used by the classes that are its instances
and the representation of the instances of those classes. The Common Lisp
Object System provides a default metaclass, standard-class, that is appropriate
for most programs. The meta-object protocol provides mechanisms for defining
and using new metaclasses.
Except where otherwise specified, all classes mentioned in this chapter are
instances of the class standard-class, all generic functions are instances of
the class standard-generic-function, and all methods are instances of the class
standard-method.
[change_end]
-------------------------------------------------------------------------------
* Defining Classes
* Creating Instances of Classes
* Slots
* Accessing Slots
-------------------------------------------------------------------------------
28.1.2.1. Defining Classes
[change_begin]
The macro defclass is used to define a new named class. The definition of a
class includes the following:
* The name of the new class. For newly defined classes this is a proper
name.
* The list of the direct superclasses of the new class.
* A set of slot specifiers. Each slot specifier includes the name of the
slot and zero or more slot options. A slot option pertains only to a
single slot. If a class definition contains two slot specifiers with the
same name, an error is signaled.
* A set of class options. Each class option pertains to the class as a
whole.
The slot options and class options of the defclass form provide mechanisms for
the following:
* Supplying a default initial value form for a given slot.
* Requesting that methods for generic functions be automatically generated
for reading or writing slots.
* Controlling whether a given slot is shared by instances of the class or
whether each instance of the class has its own slot.
* Supplying a set of initialization arguments and initialization argument
defaults to be used in instance creation.
* Indicating that the metaclass is to be other than the default.
* Indicating the expected type for the value stored in the slot.
* Indicating the documentation string for the slot.
[change_end]
-------------------------------------------------------------------------------
28.1.2.2. Creating Instances of Classes
[change_begin]
The generic function make-instance creates and returns a new instance of a
class. The Object System provides several mechanisms for specifying how a new
instance is to be initialized. For example, it is possible to specify the
initial values for slots in newly created instances either by giving arguments
to make-instance or by providing default initial values.
Further initialization activities can be performed by methods written for
generic functions that are part of the initialization protocol. The complete
initialization protocol is described in section 28.1.9.
[change_end]
-------------------------------------------------------------------------------
28.1.2.3. Slots
[change_begin]
An object that has standard-class as its metaclass has zero or more named
slots. The slots of an object are determined by the class of the object. Each
slot can hold one value. The name of a slot is a symbol that is syntactically
valid for use as a variable name.
When a slot does not have a value, the slot is said to be unbound. When an
unbound slot is read, the generic function slot-unbound is invoked. The
system-supplied primary method for slot-unbound signals an error.
The default initial value form for a slot is defined by the :initform slot
option. When the :initform form is used to supply a value, it is evaluated in
the lexical environment in which the defclass form was evaluated. The :initform
along with the lexical environment in which the defclass form was evaluated is
called a captured :initform. See section 28.1.9.
A local slot is defined to be a slot that is visible to exactly one instance,
namely the one in which the slot is allocated. A shared slot is defined to be a
slot that is visible to more than one instance of a given class and its
subclasses.
A class is said to define a slot with a given name when the defclass form for
that class contains a slot specifier with that name. Defining a local slot does
not immediately create a slot; it causes a slot to be created each time an
instance of the class is created. Defining a shared slot immediately creates a
slot.
The :allocation slot option to defclass controls the kind of slot that is
defined. If the value of the :allocation slot option is :instance, a local slot
is created. If the value of :allocation is :class, a shared slot is created.
A slot is said to be accessible in an instance of a class if the slot is
defined by the class of the instance or is inherited from a superclass of that
class. At most one slot of a given name can be accessible in an instance. A
shared slot defined by a class is accessible in all instances of that class. A
detailed explanation of the inheritance of slots is given in section 28.1.3.2.
[change_end]
-------------------------------------------------------------------------------
28.1.2.4. Accessing Slots
[change_begin]
Slots can be accessed in two ways: by use of the primitive function slot-value
and by use of generic functions generated by the defclass form.
The function slot-value can be used with any slot name specified in the
defclass form to access a specific slot accessible in an instance of the given
class.
The macro defclass provides syntax for generating methods to read and write
slots. If a reader is requested, a method is automatically generated for
reading the value of the slot, but no method for storing a value into it is
generated. If a writer is requested, a method is automatically generated for
storing a value into the slot, but no method for reading its value is
generated. If an accessor is requested, a method for reading the value of the
slot and a method for storing a value into the slot are automatically
generated. Reader and writer methods are implemented using slot-value.
When a reader or writer is specified for a slot, the name of the generic
function to which the generated method belongs is directly specified. If the
name specified for the writer option is the symbol name, the name of the
generic function for writing the slot is the symbol name, and the generic
function takes two arguments: the new value and the instance, in that order. If
the name specified for the accessor option is the symbol name, the name of the
generic function for reading the slot is the symbol name, and the name of the
generic function for writing the slot is the list (setf name).
A generic function created or modified by supplying reader, writer, or accessor
slot options can be treated exactly as an ordinary generic function.
Note that slot-value can be used to read or write the value of a slot whether
or not reader or writer methods exist for that slot. When slot-value is used,
no reader or writer methods are invoked.
The macro with-slots can be used to establish a lexical environment in which
specified slots are lexically available as if they were variables. The macro
with-slots invokes the function slot-value to access the specified slots.
The macro with-accessors can be used to establish a lexical environment in
which specified slots are lexically available through their accessors as if
they were variables. The macro with-accessors invokes the appropriate accessors
to access the specified slots. Any accessors specified by with-accessors must
already have been defined before they are used.
[change_end]
-------------------------------------------------------------------------------
28.1.3. Inheritance
[change_begin]
A class can inherit methods, slots, and some defclass options from its
superclasses. The following sections describe the inheritance of methods, the
inheritance of slots and slot options, and the inheritance of class options.
[change_end]
-------------------------------------------------------------------------------
* Inheritance of Methods
* Inheritance of Slots and Slot Options
* Inheritance of Class Options
* Examples
-------------------------------------------------------------------------------
28.1.3.1. Inheritance of Methods
[change_begin]
A subclass inherits methods in the sense that any method applicable to all
instances of a class is also applicable to all instances of any subclass of
that class.
The inheritance of methods acts the same way regardless of whether the method
was created by using one of the method-defining forms or by using one of the
defclass options that causes methods to be generated automatically.
The inheritance of methods is described in detail in section 28.1.7.
[change_end]
-------------------------------------------------------------------------------
28.1.3.2. Inheritance of Slots and Slot Options
[change_begin]
The set of names of all slots accessible in an instance of a class C is the
union of the sets of names of slots defined by C and its superclasses. The
structure of an instance is the set of names of local slots in that instance.
In the simplest case, only one class among C and its superclasses defines a
slot with a given slot name. If a slot is defined by a superclass of C, the
slot is said to be inherited. The characteristics of the slot are determined by
the slot specifier of the defining class. Consider the defining class for a
slot S. If the value of the :allocation slot option is :instance, then S is a
local slot and each instance of C has its own slot named S that stores its own
value. If the value of the :allocation slot option is :class, then S is a
shared slot, the class that defined S stores the value, and all instances of C
can access that single slot. If the :allocation slot option is omitted,
:instance is used.
In general, more than one class among C and its superclasses can define a slot
with a given name. In such cases, only one slot with the given name is
accessible in an instance of C, and the characteristics of that slot are a
combination of the several slot specifiers, computed as follows:
* All the slot specifiers for a given slot name are ordered from most
specific to least specific, according to the order in C's class precedence
list of the classes that define them. All references to the specificity of
slot specifiers immediately following refer to this ordering.
* The allocation of a slot is controlled by the most specific slot
specifier. If the most specific slot specifier does not contain an
:allocation slot option, :instance is used. Less specific slot specifiers
do not affect the allocation.
* The default initial value form for a slot is the value of the :initform
slot option in the most specific slot specifier that contains one. If no
slot specifier contains an :initform slot option, the slot has no default
initial value form.
* The contents of a slot will always be of type (and ... ) where
are the values of the :type slot options contained in all of the slot
specifiers. If no slot specifier contains the :type slot option, the
contents of the slot will always be of type t. The result of attempting to
store in a slot a value that does not satisfy the type of the slot is
undefined.
* The set of initialization arguments that initialize a given slot is the
union of the initialization arguments declared in the :initarg slot
options in all the slot specifiers.
* The documentation string for a slot is the value of the :documentation
slot option in the most specific slot specifier that contains one. If no
slot specifier contains a :documentation slot option, the slot has no
documentation string.
A consequence of the allocation rule is that a shared slot can be shadowed. For
example, if a class defines a slot named S whose value for the :allocation
slot option is :class, that slot is accessible in instances of and all of
its subclasses. However, if is a subclass of and also defines a slot
named S, 's slot is not shared by instances of and its subclasses. When a
class defines a shared slot, any subclass of will share this single
slot unless the defclass form for specifies a slot of the same name or there
is a superclass of that precedes in the class precedence list of that
defines a slot of the same name.
A consequence of the type rule is that the value of a slot satisfies the type
constraint of each slot specifier that contributes to that slot. Because the
result of attempting to store in a slot a value that does not satisfy the type
constraint for the slot is undefined, the value in a slot might fail to satisfy
its type constraint.
The :reader, :writer, and :accessor slot options create methods rather than
define the characteristics of a slot. Reader and writer methods are inherited
in the sense described in section 28.1.3.1.
Methods that access slots use only the name of the slot and the type of the
slot's value. Suppose a superclass provides a method that expects to access a
shared slot of a given name, and a subclass defines a local slot with the same
name. If the method provided by the superclass is used on an instance of the
subclass, the method accesses the local slot.
[change_end]
-------------------------------------------------------------------------------
28.1.3.3. Inheritance of Class Options
[change_begin]
The :default-initargs class option is inherited. The set of defaulted
initialization arguments for a class is the union of the sets of initialization
arguments specified in the :default-initargs class options of the class and its
superclasses. When more than one default initial value form is supplied for a
given initialization argument, the default initial value form that is used is
the one supplied by the class that is most specific according to the class
precedence list.
If a given :default-initargs class option specifies an initialization argument
of the same name more than once, an error is signaled.
[change_end]
-------------------------------------------------------------------------------
28.1.3.4. Examples
[change_begin]
(defclass C1 ()
((S1 :initform 5.4 :type number)
(S2 :allocation :class)))
(defclass C2 (C1)
((S1 :initform 5 :type integer)
(S2 :allocation :instance)
(S3 :accessor C2-S3)))
Instances of the class C1 have a local slot named S1, whose default initial
value is 5.4 and whose value should always be a number. The class C1 also has a
shared slot named S2.
There is a local slot named S1 in instances of C2. The default initial value of
S1 is 5. The value of S1 will be of type (and integer number). There are also
local slots named S2 and S3 in instances of C2. The class C2 has a method for
C2-S3 for reading the value of slot S3; there is also a method for (setf C2-S3)
that writes the value of S3.
[change_end]
-------------------------------------------------------------------------------
28.1.4. Integrating Types and Classes
[change_begin]
The Common Lisp Object System maps the space of classes into the Common Lisp
type space. Every class that has a proper name has a corresponding type with
the same name.
The proper name of every class is a valid type specifier. In addition, every
class object is a valid type specifier. Thus the expression (typep object
class) evaluates to true if the class of object is class itself or a subclass
of class. The evaluation of the expression (subtypep class1 class2) returns the
values t and t if class1 is a subclass of class2 or if they are the same class;
otherwise it returns the values nil and t. If I is an instance of some class C
named S and C is an instance of standard-class, the evaluation of the
expression (type-of I) will return S if S is the proper name of C; if S is not
the proper name of C, the expression (type-of I) will return C.
Because the names of classes and class objects are type specifiers, they may be
used in the special form the and in type declarations.
Many but not all of the predefined Common Lisp type specifiers have a
corresponding class with the same proper name as the type. These type
specifiers are listed in table 28-1. For example, the type array has a
corresponding class named array. No type specifier that is a list, such as
(vector double-float 100), has a corresponding class. The form deftype does not
create any classes.
Each class that corresponds to a predefined Common Lisp type specifier can be
implemented in one of three ways, at the discretion of each implementation. It
can be a standard class (of the kind defined by defclass), a structure class
(defined by defstruct), or a built-in class (implemented in a special,
non-extensible way).
A built-in class is one whose instances have restricted capabilities or special
representations. Attempting to use defclass to define subclasses of a built-in
class signals an error. Calling make-instance to create an instance of a
built-in class signals an error. Calling slot-value on an instance of a
built-in class signals an error. Redefining a built-in class or using
change-class to change the class of an instance to or from a built-in class
signals an error. However, built-in classes can be used as parameter
specializers in methods.
It is possible to determine whether a class is a built-in class by checking the
metaclass. A standard class is an instance of standard-class, a built-in class
is an instance of built-in-class, and a structure class is an instance of
structure-class.
Each structure type created by defstruct without using the :type option has a
corresponding class. This class is an instance of structure-class.
The :include option of defstruct creates a direct subclass of the class that
corresponds to the included structure.
The purpose of specifying that many of the standard Common Lisp type specifiers
have a corresponding class is to enable users to write methods that
discriminate on these types. Method selection requires that a class precedence
list can be determined for each class.
The hierarchical relationships among the Common Lisp type specifiers are
mirrored by relationships among the classes corresponding to those types. The
existing type hierarchy is used for determining the class precedence list for
each class that corresponds to a predefined Common Lisp type. In some cases,
the first edition did not specify a local precedence order for two supertypes
of a given type specifier. For example, null is a subtype of both symbol and
list, but the first edition did not specify whether symbol is more specific or
less specific than list. The CLOS specification defines those relationships for
all such classes.
Table 28-1 lists the set of classes required by the Object System that
correspond to predefined Common Lisp type specifiers. The superclasses of each
such class are presented in order from most specific to most general, thereby
defining the class precedence list for the class. The local precedence order
for each class that corresponds to a Common Lisp type specifier can be derived
from this table.
Individual implementations may be extended to define other type specifiers to
have a corresponding class. Individual implementations can be extended to add
other subclass relationships and to add other elements to the class precedence
lists in the above table as long as they do not violate the type relationships
and disjointness requirements specified in section 2.15. A standard class
defined with no direct superclasses is guaranteed to be disjoint from all of
the classes in the table, except for the class named t.
[At this point the original CLOS report specified that certain Common Lisp
types were to appear in table 28-1 if and only if X3J13 voted to make them
disjoint from cons, symbol, array, number, and character. X3J13 voted to do so
in June 1988 (DATA-TYPES-HIERARCHY-UNDERSPECIFIED) . I have added these types
and their class precedence lists to the table; the new types are indicated by
asterisks.-GLS]
----------------------------------------------------------------
Table 28-1: Class Precedence Lists for Predefined Types
Predefined Class Precedence List
Common Lisp Type for Corresponding Class
==============================================================
array (array t)
bit-vector (bit-vector vector array sequence t)
character (character t)
complex (complex number t)
cons (cons list sequence t)
float (float number t)
function * (function t)
hash-table * (hash-table t)
integer (integer rational number t)
list (list sequence t)
null (null symbol list sequence t)
number (number t)
package * (package t)
pathname * (pathname t)
random-state * (random-state t)
ratio (ratio rational number t)
rational (rational number t)
readtable * (readtable t)
sequence (sequence t)
stream * (stream t)
string (string vector array sequence t)
symbol (symbol t)
t (t)
vector (vector array sequence t)
==============================================================
[An asterisk indicates a type added to this table as a consequence of
a portion of the CLOS specification that was conditional on X3J13
voting to make that type disjoint from certain other built-in types
(DATA-TYPES-HIERARCHY-UNDERSPECIFIED).---GLS]
----------------------------------------------------------------
[change_end]
-------------------------------------------------------------------------------
28.1.5. Determining the Class Precedence List
[change_begin]
The defclass form for a class provides a total ordering on that class and its
direct superclasses. This ordering is called the local precedence order. It is
an ordered list of the class and its direct superclasses. The class precedence
list for a class C is a total ordering on C and its superclasses that is
consistent with the local precedence orders for C and its superclasses.
A class precedes its direct superclasses, and a direct superclass precedes all
other direct superclasses specified to its right in the superclasses list of
the defclass form. For every class C, define
where are the direct superclasses of C in the order in which they are
mentioned in the defclass form. These ordered pairs generate the total ordering
on the class C and its direct superclasses.
Let be the set of C and its superclasses. Let R be
The set R may or may not generate a partial ordering, depending on whether the
, , are consistent; it is assumed that they are consistent and that R
generates a partial ordering. When the are not consistent, it is said that R
is inconsistent.
To compute the class precedence list for C, topologically sort the elements of
with respect to the partial ordering generated by R. When the topological
sort must select a class from a set of two or more classes, none of which are
preceded by other classes with respect to R, the class selected is chosen
deterministically, as described below. If R is inconsistent, an error is
signaled.
[change_end]
-------------------------------------------------------------------------------
* Topological Sorting
* Examples
-------------------------------------------------------------------------------
28.1.5.1. Topological Sorting
[change_begin]
Topological sorting proceeds by finding a class C in such that no other
class precedes that element according to the elements in R. The class C is
placed first in the result. Remove C from , and remove all pairs of the form
(C, D), , from R. Repeat the process, adding classes with no predecessors to
the end of the result. Stop when no element can be found that has no
predecessor.
If is not empty and the process has stopped, the set R is inconsistent. If
every class in the finite set of classes is preceded by another, then R
contains a loop. That is, there is a chain of classes such that precedes
, 1 <= i < n, and precedes .
Sometimes there are several classes from with no predecessors. In this case
select the one that has a direct subclass rightmost in the class precedence
list computed so far.
If there is no such candidate class, R does not generate a partial ordering -
the , , are inconsistent.
In more precise terms, let , m >= 2, be the classes from with no
predecessors. Let , n >= 1, be the class precedence list constructed so far.
is the most specific class, and is the least specific. Let 1 <= j <= n be
the largest number such that there exists an i where 1 <= i <= m and is a
direct superclass of ; is placed next.
The effect of this rule for selecting from a set of classes with no
predecessors is that classes in a simple superclass chain are adjacent in the
class precedence list and that classes in each relatively separated subgraph
are adjacent in the class precedence list. For example, let and be
subgraphs whose only element in common is the class J. Suppose that no
superclass of J appears in either or . Let be the bottom of ; and let
be the bottom of . Suppose C is a class whose direct superclasses are
and in that order; then the class precedence list for C will start with C
and will be followed by all classes in except J. All the classes of will
be next. The class J and its superclasses will appear last.
[change_end]
-------------------------------------------------------------------------------
28.1.5.2. Examples
[change_begin]
This example determines a class precedence list for the class pie. The
following classes are defined:
(defclass pie (apple cinnamon) ())
(defclass apple (fruit) ())
(defclass cinnamon (spice) ())
(defclass fruit (food) ())
(defclass spice (food) ())
(defclass food () ())
The set S = {pie, apple, cinnamon, fruit, spice, food, standard-object, t}. The
set R = {(pie, apple), (apple, cinnamon), (cinnamon, standard-object), (apple,
fruit), (fruit, standard-object), (cinnamon, spice), (spice, standard-object),
(fruit, food), (food, standard-object), (spice, food), (standard-object, t)}
[The original CLOS specification [5,6] contained a minor error in this example:
the pairs (cinnamon, standard-object), (fruit, standard-object), and (spice,
standard-object) were inadvertently omitted from R in the preceding paragraph.
It is important to understand that defclass implicitly appends the class
standard-object to the list of superclasses when the metaclass is
standard-class (the normal situation), in order to insure that standard-object
will be a superclass of every instance of standard-class except standard-object
itself (see section 28.1.2). is then generated from this augmented list of
superclasses; this is where the extra pairs come from. I have corrected the
example by adding these pairs as appropriate throughout the example. The final
result, the class precedence list for pie, is unchanged.-GLS]
The class pie is not preceded by anything, so it comes first; the result so far
is (pie). Remove pie from S and pairs mentioning pie from R to get
S = {apple, cinnamon, fruit, spice, food, standard-object, t} and R = {(apple,
cinnamon), (cinnamon, standard-object), (apple, fruit), (fruit,
standard-object), (cinnamon, spice), (spice, standard-object), (fruit, food),
(food, standard-object), (spice, food), (standard-object, t)}.
The class apple is not preceded by anything, so it is next; the result is (pie
apple). Removing apple and the relevant pairs results in
S = {cinnamon, fruit, spice, food, standard-object, t} and R = {(cinnamon,
standard-object), (fruit, standard-object), (cinnamon, spice), (spice,
standard-object), (fruit, food), (food, standard-object), (spice, food),
(standard-object, t)}.
The classes cinnamon and fruit are not preceded by anything, so the one with a
direct subclass rightmost in the class precedence list computed so far goes
next. The class apple is a direct subclass of fruit, and the class pie is a
direct subclass of cinnamon. Because apple appears to the right of pie in the
precedence list, fruit goes next, and the result so far is (pie apple fruit).
S = {cinnamon, spice, food, standard-object, t} and R = {(cinnamon,
standard-object), (cinnamon, spice), (spice, standard-object), (food,
standard-object), (spice, food), (standard-object, t)}.
The class cinnamon is next, giving the result so far as (pie apple fruit
cinnamon). At this point
S = {spice, food, standard-object, t} and R = {(spice, standard-object), (food,
standard-object), (spice, food), (standard-object, t)}.
The classes spice, food, standard-object, and t are then added in that order,
and the final class precedence list for pie is
(pie apple fruit cinnamon spice food standard-object t)
It is possible to write a set of class definitions that cannot be ordered. For
example:
(defclass new-class (fruit apple) ())
(defclass apple (fruit) ())
The class fruit must precede apple because the local ordering of superclasses
must be preserved. The class apple must precede fruit because a class always
precedes its own superclasses. When this situation occurs, an error is signaled
when the system tries to compute the class precedence list.
The following might appear to be a conflicting set of definitions:
(defclass pie (apple cinnamon) ())
(defclass pastry (cinnamon apple) ())
(defclass apple () ())
(defclass cinnamon () ())
The class precedence list for pie is
(pie apple cinnamon standard-object t)
The class precedence list for pastry is
(pastry cinnamon apple standard-object t)
It is not a problem for apple to precede cinnamon in the ordering of the
superclasses of pie but not in the ordering for pastry. However, it is not
possible to build a new class that has both pie and pastry as superclasses.
[change_end]
-------------------------------------------------------------------------------
28.1.6. Generic Functions and Methods
[change_begin]
A generic function is a function whose behavior depends on the classes or
identities of the arguments supplied to it. The methods define the
class-specific behavior and operations of the generic function. The following
sections describe generic functions and methods.
[change_end]
-------------------------------------------------------------------------------
* Introduction to Generic Functions
* Introduction to Methods
* Agreement on Parameter Specializers and Qualifiers
* Congruent Lambda-Lists for All Methods of a Generic Function
* Keyword Arguments in Generic Functions and Methods
-------------------------------------------------------------------------------
28.1.6.1. Introduction to Generic Functions
[change_begin]
A generic function object contains a set of methods, a lambda-list, a method
combination type, and other information.
Like an ordinary Lisp function, a generic function takes arguments, performs a
series of operations, and perhaps returns useful values. An ordinary function
has a single body of code that is always executed when the function is called.
A generic function has a set of bodies of code of which a subset is selected
for execution. The selected bodies of code and the manner of their combination
are determined by the classes or identities of one or more of the arguments to
the generic function and by its method combination type.
Ordinary functions and generic functions are called with identical
function-call syntax.
Generic functions are true functions that can be passed as arguments, returned
as values, used as the first argument to funcall and apply, and otherwise used
in all the ways an ordinary function may be used.
A name can be given to an ordinary function in one of two ways: a global name
can be given to a function using the defun construct; a local name can be given
using the flet or labels special forms. A generic function can be given a
global name using the defmethod or defgeneric construct. A generic function can
be given a local name using the generic-flet, generic-labels, or
with-added-methods special forms. The name of a generic function, like the name
of an ordinary function, can be either a symbol or a two-element list whose
first element is setf and whose second element is a symbol. This is true for
both local and global names.
The generic-flet special form creates new local generic functions using the set
of methods specified by the method definitions in the generic-flet form. The
scoping of generic function names within a generic-flet form is the same as for
flet.
The generic-labels special form creates a set of new mutually recursive local
generic functions using the set of methods specified by the method definitions
in the generic-labels form. The scoping of generic function names within a
generic-labels form is the same as for labels.
The with-added-methods special form creates new local generic functions by
adding the set of methods specified by the method definitions with a given name
in the with-added-methods form to copies of the methods of the lexically
visible generic function of the same name. If there is a lexically visible
ordinary function of the same name as one of the specified generic functions,
that function becomes the method function of the default method for the new
generic function of that name.
The generic-function macro creates an anonymous generic function with the set
of methods specified by the method definitions that appear in the
generic-function form.
When a defgeneric form is evaluated, one of three actions is taken:
* If a generic function of the given name already exists, the existing
generic function object is modified. Methods specified by the current
defgeneric form are added, and any methods in the existing generic
function that were defined by a previous defgeneric form are removed.
Methods added by the current defgeneric form might replace methods defined
by defmethod or defclass. No other methods in the generic function are
affected or replaced.
* If the given name names a non-generic function, a macro, or a special
form, an error is signaled.
* Otherwise a generic function is created with the methods specified by the
method definitions in the defgeneric form.
Some forms specify the options of a generic function, such as the type of
method combination it uses or its argument precedence order. They will be
referred to as ``forms that specify generic function options.'' These forms are
defgeneric, generic-function, generic-flet, generic-labels, and
with-added-methods.
Some forms define methods for a generic function. They will be referred to as
``method-defining forms.'' These forms are defgeneric, defmethod,
generic-function, generic-flet, generic-labels, with-added-methods, and
defclass. Note that all the method-defining forms except defclass and defmethod
are also forms that specify generic function options.
[change_end]
-------------------------------------------------------------------------------
28.1.6.2. Introduction to Methods
[change_begin]
A method object contains a method function, a sequence of parameter
specializers that specify when the given method is applicable, a lambda-list,
and a sequence of qualifiers that are used by the method combination facility
to distinguish among methods.
A method object is not a function and cannot be invoked as a function. Various
mechanisms in the Object System take a method object and invoke its method
function, as is the case when a generic function is invoked. When this occurs
it is said that the method is invoked or called.
A method-defining form contains the code that is to be run when the arguments
to the generic function cause the method that it defines to be invoked. When a
method-defining form is evaluated, a method object is created and one of four
actions is taken:
* If a generic function of the given name already exists and if a method
object already exists that agrees with the new one on parameter
specializers and qualifiers, the new method object replaces the old one.
For a definition of one method agreeing with another on parameter
specializers and qualifiers, see section 28.1.6.3.
* If a generic function of the given name already exists and if there is no
method object that agrees with the new one on parameter specializers and
qualifiers, the existing generic function object is modified to contain
the new method object.
* If the given name names a non-generic function, a macro, or a special
form, an error is signaled.
* Otherwise a generic function is created with the methods specified by the
method-defining form.
If the lambda-list of a new method is not congruent with the lambda-list of the
generic function, an error is signaled. If a method-defining form that cannot
specify generic function options creates a new generic function, a lambda-list
for that generic function is derived from the lambda-lists of the methods in
the method-defining form in such a way as to be congruent with them. For a
discussion of congruence, see section 28.1.6.4.
Each method has a specialized lambda-list, which determines when that method
can be applied. A specialized lambda-list is like an ordinary lambda-list
except that a specialized parameter may occur instead of the name of a required
parameter. A specialized parameter is a list (variable-name
parameter-specializer-name), where parameter-specializer-name is either a name
that names a class or a list (eql form). A parameter specializer name denotes a
parameter specializer as follows:
* A name that names a class denotes that class.
* The list (eql form) denotes the type specifier (eql object), where object
is the result of evaluating form. The form form is evaluated in the
lexical environment in which the method-defining form is evaluated. Note
that form is evaluated only once, at the time the method is defined, not
each time the generic function is called.
Parameter specializer names are used in macros intended as the user-level
interface (defmethod), while parameter specializers are used in the functional
interface.
[It is very important to understand clearly the distinction made in the
preceding paragraph. A parameter specializer name has the form of a type
specifier but is semantically quite different from a type specifier: a
parameter specializer name of the form (eql form) is not a type specifier, for
it contains a form to be evaluated. Type specifiers never contain forms to be
evaluated. All parameter specializers (as opposed to parameter specializer
names) are valid type specifiers, but not all type specifiers are valid
names and treat them as specifications for constructing certain type specifiers
(parameter specializers) that may then be used with such functions as
find-method.-GLS]
Only required parameters may be specialized, and there must be a parameter
specializer for each required parameter. For notational simplicity, if some
required parameter in a specialized lambda-list in a method-defining form is
simply a variable name, its parameter specializer defaults to the class named
t.
Given a generic function and a set of arguments, an applicable method is a
method for that generic function whose parameter specializers are satisfied by
their corresponding arguments. The following definition specifies what it means
for a method to be applicable and for an argument to satisfy a parameter
specializer.
Let be the required arguments to a generic function in order. Let be the
parameter specializers corresponding to the required parameters of the method M
in order. The method M is applicable when each satisfies . If is a
class, and if is an instance of a class C, then it is said that satisfies
when or when C is a subclass of . If is of the form (eql object),
then it is said that satisfies when the function eql applied to and
object is true.
Because a parameter specializer is a type specifier, the function typep can be
used during method selection to determine whether an argument satisfies a
parameter specializer. In general a parameter specializer cannot be a type
specifier list, such as (vector single-float). The only parameter specializer
that can be a list is (eql object). This requires that Common Lisp define the
type specifier eql as if the following were evaluated:
(deftype eql (object) `(member ,object))
[See section 4.3.-GLS]
A method all of whose parameter specializers are the class named t is called a
default method; it is always applicable but may be shadowed by a more specific
method.
Methods can have qualifiers, which give the method combination procedure a way
to distinguish among methods. A method that has one or more qualifiers is
called a qualified method. A method with no qualifiers is called an unqualified
method. A qualifier is any object other than a list, that is, any non-nil atom.
The qualifiers defined by standard method combination and by the built-in
method combination types are symbols.
In this specification, the terms primary method and auxiliary method are used
to partition methods within a method combination type according to their
intended use. In standard method combination, primary methods are unqualified
methods, and auxiliary methods are methods with a single qualifier that is one
of :around, :before, or :after. When a method combination type is defined using
the short form of define-method-combination, primary methods are methods
qualified with the name of the type of method combination, and auxiliary
methods have the qualifier :around. Thus the terms primary method and auxiliary
method have only a relative definition within a given method combination type.
[change_end]
-------------------------------------------------------------------------------
28.1.6.3. Agreement on Parameter Specializers and Qualifiers
[change_begin]
Two methods are said to agree with each other on parameter specializers and
qualifiers if the following conditions hold:
* Both methods have the same number of required parameters. Suppose the
parameter specializers of the two methods are and .
* For each 1 <= i <= n, agrees with . The parameter specializer
agrees with if and are the same class or if , , and (eql
). Otherwise and do not agree.
* The lists of qualifiers of both methods contain the same non-nil atoms in
the same order. That is, the lists are equal.
[change_end]
-------------------------------------------------------------------------------
28.1.6.4. Congruent Lambda-Lists for All Methods of a Generic Function
[change_begin]
These rules define the congruence of a set of lambda-lists, including the
lambda-list of each method for a given generic function and the lambda-list
specified for the generic function itself, if given.
* Each lambda-list must have the same number of required parameters.
* Each lambda-list must have the same number of optional parameters. Each
method can supply its own default for an optional parameter.
* If any lambda-list mentions &rest or &key, each lambda-list must mention
one or both of them.
* If the generic function lambda-list mentions &key, each method must
accept all of the keyword names mentioned after &key, either by accepting
them explicitly, by specifying &allow-other-keys, or by specifying &rest
but not &key. Each method can accept additional keyword arguments of its
own. The checking of the validity of keyword names is done in the generic
function, not in each method. A method is invoked as if the keyword
argument pair whose keyword is :allow-other-keys and whose value is t were
supplied, though no such argument pair will be passed.
* The use of &allow-other-keys need not be consistent across lambda-lists.
If &allow-other-keys is mentioned in the lambda-list of any applicable
method or of the generic function, any keyword arguments may be mentioned
in the call to the generic function.
* The use of &aux need not be consistent across methods.
If a method-defining form that cannot specify generic function options creates
a generic function, and if the lambda-list for the method mentions keyword
arguments, the lambda-list of the generic function will mention &key (but no
keyword arguments).
[change_end]
-------------------------------------------------------------------------------
28.1.6.5. Keyword Arguments in Generic Functions and Methods
[change_begin]
When a generic function or any of its methods mentions &key in a lambda-list,
the specific set of keyword arguments accepted by the generic function varies
according to the applicable methods. The set of keyword arguments accepted by
the generic function for a particular call is the union of the keyword
arguments accepted by all applicable methods and the keyword arguments
mentioned after &key in the generic function definition, if any. A method that
has &rest but not &key does not affect the set of acceptable keyword arguments.
If the lambda-list of any applicable method or of the generic function
definition contains &allow-other-keys, all keyword arguments are accepted by
the generic function.
The lambda-list congruence rules require that each method accept all of the
keyword arguments mentioned after &key in the generic function definition, by
accepting them explicitly, by specifying &allow-other-keys, or by specifying
&rest but not &key. Each method can accept additional keyword arguments of its
own, in addition to the keyword arguments mentioned in the generic function
definition.
If a generic function is passed a keyword argument that no applicable method
accepts, an error is signaled.
For example, suppose there are two methods defined for width as follows:
(defmethod width ((c character-class) &key font) ...)
(defmethod width ((p picture-class) &key pixel-size) ...)
Assume that there are no other methods and no generic function definition for
width. The evaluation of the following form will signal an error because the
keyword argument :pixel-size is not accepted by the applicable method.
(width (make-instance 'character-class :char #\Q)
:font 'baskerville :pixel-size 10)
The evaluation of the following form will signal an error.
(width (make-instance 'picture-class :glyph (glyph #\Q))
:font 'baskerville :pixel-size 10)
The evaluation of the following form will not signal an error if the class
named character-picture-class is a subclass of both picture-class and
character-class.
(width (make-instance 'character-picture-class :char #\Q)
:font 'baskerville :pixel-size 10)
[change_end]
-------------------------------------------------------------------------------
28.1.7. Method Selection and Combination
[change_begin]
When a generic function is called with particular arguments, it must determine
the code to execute. This code is called the effective method for those
arguments. The effective method is a combination of the applicable methods in
the generic function. A combination of methods is a Lisp expression that
contains calls to some or all of the methods. If a generic function is called
and no methods apply, the generic function no-applicable-method is invoked.
When the effective method has been determined, it is invoked with the same
arguments that were passed to the generic function. Whatever values it returns
are returned as the values of the generic function.
[change_end]
-------------------------------------------------------------------------------
* Determining the Effective Method
* Standard Method Combination
* Declarative Method Combination
* Built-in Method Combination Types
-------------------------------------------------------------------------------
28.1.7.1. Determining the Effective Method
[change_begin]
The effective method for a set of arguments is determined by the following
three-step procedure:
1. Select the applicable methods.
2. Sort the applicable methods by precedence order, putting the most
specific method first.
3. Apply method combination to the sorted list of applicable methods,
producing the effective method.
Selecting the Applicable Methods. This step is described in section 28.1.6.2.
Sorting the Applicable Methods by Precedence Order. To compare the precedence
of two methods, their parameter specializers are examined in order. The default
examination order is from left to right, but an alternative order may be
specified by the :argument-precedence-order option to defgeneric or to any of
the other forms that specify generic function options.
The corresponding parameter specializers from each method are compared. When a
pair of parameter specializers are equal, the next pair are compared for
equality. If all corresponding parameter specializers are equal, the two
methods must have different qualifiers; in this case, either method can be
selected to precede the other.
If some corresponding parameter specializers are not equal, the first pair of
parameter specializers that are not equal determines the precedence. If both
parameter specializers are classes, the more specific of the two methods is the
method whose parameter specializer appears earlier in the class precedence list
of the corresponding argument. Because of the way in which the set of
applicable methods is chosen, the parameter specializers are guaranteed to be
present in the class precedence list of the class of the argument.
If just one parameter specializer is (eql object), the method with that
parameter specializer precedes the other method. If both parameter specializers
are eql forms, the specializers must be the same (otherwise the two methods
would not both have been applicable to this argument).
The resulting list of applicable methods has the most specific method first and
the least specific method last.
Applying Method Combination to the Sorted List of Applicable Methods. In the
simple case-if standard method combination is used and all applicable methods
are primary methods-the effective method is the most specific method. That
method can call the next most specific method by using the function
call-next-method. The method that call-next-method will call is referred to as
the next method. The predicate next-method-p tests whether a next method
exists. If call-next-method is called and there is no next most specific
method, the generic function no-next-method is invoked.
In general, the effective method is some combination of the applicable methods.
It is defined by a Lisp form that contains calls to some or all of the
applicable methods, returns the value or values that will be returned as the
value or values of the generic function, and optionally makes some of the
methods accessible by means of call-next-method. This Lisp form is the body of
the effective method; it is augmented with an appropriate lambda-list to make
it a function.
The role of each method in the effective method is determined by its method
qualifiers and the specificity of the method. A qualifier serves to mark a
method, and the meaning of a qualifier is determined by the way that these
marks are used by this step of the procedure. If an applicable method has an
unrecognized qualifier, this step signals an error and does not include that
method in the effective method.
When standard method combination is used together with qualified methods, the
effective method is produced as described in section 28.1.7.2.
Another type of method combination can be specified by using the
:method-combination option of defgeneric or of any of the other forms that
specify generic function options. In this way this step of the procedure can be
customized.
New types of method combination can be defined by using the
define-method-combination macro.
The meta-object level also offers a mechanism for defining new types of method
combination. The generic function compute-effective-method receives as
arguments the generic function, the method combination object, and the sorted
list of applicable methods. It returns the Lisp form that defines the effective
method. A method for compute-effective-method can be defined directly by using
defmethod or indirectly by using define-method-combination. A method
combination object is an object that encapsulates the method combination type
and options specified by the :method-combination option to forms that specify
generic function options.
-------------------------------------------------------------------------------
Implementation note: In the simplest implementation, the generic function would
compute the effective method each time it was called. In practice, this will be
too inefficient for some implementations. Instead, these implementations might
employ a variety of optimizations of the three-step procedure. Some
illustrative examples of such optimizations are the following:
* Use a hash table keyed by the class of the arguments to store the
effective method.
* Compile the effective method and save the resulting compiled function in
a table.
* Recognize the Lisp form as an instance of a pattern of control structure
and substitute a closure that implements that structure.
* Examine the parameter specializers of all methods for the generic
function and enumerate all possible effective methods. Combine the
effective methods, together with code to select from among them, into a
single function and compile that function. Call that function whenever the
generic function is called.
-------------------------------------------------------------------------------
[change_end]
-------------------------------------------------------------------------------
28.1.7.2. Standard Method Combination
[change_begin]
Standard method combination is supported by the class
standard-generic-function. It is used if no other type of method combination is
specified or if the built-in method combination type standard is specified.
Primary methods define the main action of the effective method, while auxiliary
methods modify that action in one of three ways. A primary method has no method
qualifiers.
An auxiliary method is a method whose method qualifier is :before, :after, or
:around. Standard method combination allows no more than one qualifier per
method; if a method definition specifies more than one qualifier per method, an
error is signaled.
* A :before method has the keyword :before as its only qualifier. A :before
method specifies code that is to be run before any primary method.
* An :after method has the keyword :after as its only qualifier. An :after
method specifies code that is to be run after primary methods.
* An :around method has the keyword :around as its only qualifier. An
:around method specifies code that is to be run instead of other
applicable methods but that is able to cause some of them to be run.
The semantics of standard method combination are as follows:
* If there are any :around methods, the most specific :around method is
called. It supplies the value or values of the generic function.
* Inside the body of an :around method, call-next-method can be used to
call the next method. When the next method returns, the :around method can
execute more code, perhaps based on the returned value or values. The
generic function no-next-method is invoked if call-next-method is used and
there is no applicable method to call. The function next-method-p may be
used to determine whether a next method exists.
* If an :around method invokes call-next-method, the next most specific
:around method is called, if one is applicable. If there are no :around
methods or if call-next-method is called by the least specific :around
method, the other methods are called as follows:
o All the :before methods are called, in most-specific-first order.
Their values are ignored. An error is signaled if call-next-method is
used in a :before method.
o The most specific primary method is called. Inside the body of a
primary method, call-next-method may be used to call the next most
specific primary method. When that method returns, the previous
primary method can execute more code, perhaps based on the returned
value or values. The generic function no-next-method is invoked if
call-next-method is used and there are no more applicable primary
methods. The function next-method-p may be used to determine whether
a next method exists. If call-next-method is not used, only the most
specific primary method is called.
o All the :after methods are called in most-specific-last order. Their
values are ignored. An error is signaled if call-next-method is used
in an :after method.
* If no :around methods were invoked, the most specific primary method
supplies the value or values returned by the generic function. The value
or values returned by the invocation of call-next-method in the least
specific :around method are those returned by the most specific primary
method.
In standard method combination, if there is an applicable method but no
applicable primary method, an error is signaled.
The :before methods are run in most-specific-first order and the :after methods
are run in least-specific-first order. The design rationale for this difference
can be illustrated with an example. Suppose class modifies the behavior of
its superclass, , by adding :before and :after methods. Whether the behavior
of the class is defined directly by methods on or is inherited from its
superclasses does not affect the relative order of invocation of methods on
instances of the class . Class 's :before method runs before all of class
's methods. Class 's :after method runs after all of class 's methods.
By contrast, all :around methods run before any other methods run. Thus a less
specific :around method runs before a more specific primary method.
If only primary methods are used and if call-next-method is not used, only the
most specific method is invoked; that is, more specific methods shadow more
general ones.
[change_end]
-------------------------------------------------------------------------------
28.1.7.3. Declarative Method Combination
[change_begin]
The macro define-method-combination defines new forms of method combination. It
provides a mechanism for customizing the production of the effective method.
The default procedure for producing an effective method is described in section
28.1.7.2. There are two forms of define-method-combination. The short form is a
simple facility; the long form is more powerful and more verbose. The long form
resembles defmacro in that the body is an expression that computes a Lisp form;
it provides mechanisms for implementing arbitrary control structures within
method combination and for arbitrary processing of method qualifiers. The
syntax and use of both forms of define-method-combination are explained in
section 28.2.
[change_end]
-------------------------------------------------------------------------------
28.1.7.4. Built-in Method Combination Types
[change_begin]
The Common Lisp Object System provides a set of built-in method combination
types. To specify that a generic function is to use one of these method
combination types, the name of the method combination type is given as the
argument to the :method-combination option to defgeneric or to the
:method-combination option to any of the other forms that specify generic
function options.
The names of the built-in method combination types are +, and, append, list,
max, min, nconc, or, progn, and standard.
The semantics of the standard built-in method combination type were described
in section 28.1.7.2. The other built-in method combination types are called
simple built-in method combination types.
The simple built-in method combination types act as though they were defined by
the short form of define-method-combination. They recognize two roles for
methods:
* An :around method has the keyword symbol :around as its sole qualifier.
The meaning of :around methods is the same as in standard method
combination. Use of the functions call-next-method and next-method-p is
supported in :around methods.
* A primary method has the name of the method combination type as its sole
qualifier. For example, the built-in method combination type and
recognizes methods whose sole qualifier is and; these are primary methods.
Use of the functions call-next-method and next-method-p is not supported
in primary methods.
The semantics of the simple built-in method combination types are as follows:
* If there are any :around methods, the most specific :around method is
called. It supplies the value or values of the generic function.
* Inside the body of an :around method, the function call-next-method can
be used to call the next method. The generic function no-next-method is
invoked if call-next-method is used and there is no applicable method to
call. The function next-method-p may be used to determine whether a next
method exists. When the next method returns, the :around method can
execute more code, perhaps based on the returned value or values.
* If an :around method invokes call-next-method, the next most specific
:around method is called, if one is applicable. If there are no :around
methods or if call-next-method is called by the least specific :around
method, a Lisp form derived from the name of the built-in method
combination type and from the list of applicable primary methods is
evaluated to produce the value of the generic function. Suppose the name
of the method combination type is operator and the call to the generic
function is of the form
(generic-function ... )
Let be the applicable primary methods in order; then the derived Lisp
form is
(operator
... )
If the expression is evaluated, the method will be applied to the
arguments . For example, if operator is or, the expression is
evaluated only if , 1 <= j < i, returned nil.
The default order for the primary methods is :most-specific-first.
However, the order can be reversed by supplying :most-specific-last as the
second argument to the :method-combination option.
The simple built-in method combination types require exactly one qualifier per
method. An error is signaled if there are applicable methods with no qualifiers
or with qualifiers that are not supported by the method combination type. An
error is signaled if there are applicable :around methods and no applicable
primary methods.
[change_end]
-------------------------------------------------------------------------------
28.1.8. Meta-objects
[change_begin]
The implementation of the Object System manipulates classes, methods, and
generic functions. The meta-object protocol specifies a set of generic
functions defined by methods on classes; the behavior of those generic
functions defines the behavior of the Object System. The instances of the
classes on which those methods are defined are called meta-objects. Programming
at the meta-object protocol level involves defining new classes of meta-objects
along with methods specialized on these classes.
[change_end]
-------------------------------------------------------------------------------
* Metaclasses
* Standard Metaclasses
* Standard Meta-objects
-------------------------------------------------------------------------------
28.1.8.1. Metaclasses
[change_begin]
The metaclass of an object is the class of its class. The metaclass determines
the representation of instances of its instances and the forms of inheritance
used by its instances for slot descriptions and method inheritance. The
metaclass mechanism can be used to provide particular forms of optimization or
to tailor the Common Lisp Object System for particular uses. The protocol for
defining metaclasses is discussed in the third part of the CLOS specification,
The Common Lisp Object System Meta-Object Protocol. [The third part has not yet
been approved by X3J13 for inclusion in the forthcoming Common Lisp standard
and is not included in this book.-GLS]
[change_end]
-------------------------------------------------------------------------------
28.1.8.2. Standard Metaclasses
[change_begin]
The Common Lisp Object System provides a number of predefined metaclasses.
These include the classes standard-class, built-in-class, and structure-class:
* The class standard-class is the default class of classes defined by
defclass.
* The class built-in-class is the class whose instances are classes that
have special implementations with restricted capabilities. Any class that
corresponds to a standard Common Lisp type might be an instance of
built-in-class. The predefined Common Lisp type specifiers that are
required to have corresponding classes are listed in table 28-1. It is
implementation-dependent whether each of these classes is implemented as a
built-in class.
* All classes defined by means of defstruct are instances of
structure-class.
[change_end]
-------------------------------------------------------------------------------
28.1.8.3. Standard Meta-objects
[change_begin]
The Object System supplies a standard set of meta-objects, called standard
meta-objects. These include the class standard-object and instances of the
classes standard-method, standard-generic-function, and method-combination.
* The class standard-method is the default class of methods that are
defined by the forms defmethod, defgeneric, generic-function,
generic-flet, generic-labels, and with-added-methods.
* The class standard-generic-function is the default class of generic
functions defined by the forms defmethod, defgeneric, generic-function,
generic-flet, generic-labels, with-added-methods, and defclass.
* The class named standard-object is an instance of the class
standard-class and is a superclass of every class that is an instance of
standard-class except itself.
* Every method combination object is an instance of a subclass of the class
method-combination.
[change_end]
-------------------------------------------------------------------------------
28.1.9. Object Creation and Initialization
[change_begin]
The generic function make-instance creates and returns a new instance of a
class. The first argument is a class or the name of a class, and the remaining
arguments form an initialization argument list.
The initialization of a new instance consists of several distinct steps,
including the following: combining the explicitly supplied initialization
arguments with default values for the unsupplied initialization arguments,
checking the validity of the initialization arguments, allocating storage for
the instance, filling slots with values, and executing user-supplied methods
that perform additional initialization. Each step of make-instance is
implemented by a generic function to provide a mechanism for customizing that
step. In addition, make-instance is itself a generic function and thus also can
be customized.
The Object System specifies system-supplied primary methods for each step and
thus specifies a well-defined standard behavior for the entire initialization
process. The standard behavior provides four simple mechanisms for controlling
initialization:
* Declaring a symbol to be an initialization argument for a slot. An
initialization argument is declared by using the :initarg slot option to
defclass. This provides a mechanism for supplying a value for a slot in a
call to make-instance.
* Supplying a default value form for an initialization argument. Default
value forms for initialization arguments are defined by using the
:default-initargs class option to defclass. If an initialization argument
is not explicitly provided as an argument to make-instance, the default
value form is evaluated in the lexical environment of the defclass form
that defined it, and the resulting value is used as the value of the
initialization argument.
* Supplying a default initial value form for a slot. A default initial
value form for a slot is defined by using the :initform slot option to
defclass. If no initialization argument associated with that slot is given
as an argument to make-instance or is defaulted by :default-initargs, this
default initial value form is evaluated in the lexical environment of the
defclass form that defined it, and the resulting value is stored in the
slot. The :initform form for a local slot may be used when creating an
instance, when updating an instance to conform to a redefined class, or
when updating an instance to conform to the definition of a different
class. The :initform form for a shared slot may be used when defining or
re-defining the class.
* Defining methods for initialize-instance and shared-initialize. The
slot-filling behavior described above is implemented by a system-supplied
primary method for initialize-instance which invokes shared-initialize.
The generic function shared-initialize implements the parts of
initialization shared by these four situations: when making an instance,
when re-initializing an instance, when updating an instance to conform to
a redefined class, and when updating an instance to conform to the
definition of a different class. The system-supplied primary method for
shared-initialize directly implements the slot-filling behavior described
above, and initialize-instance simply invokes shared-initialize.
[change_end]
-------------------------------------------------------------------------------
* Initialization Arguments
* Declaring the Validity of Initialization Arguments
* Defaulting of Initialization Arguments
* Rules for Initialization Arguments
* Shared-Initialize
* Initialize-Instance
* Definitions of Make-Instance and Initialize-Instance
-------------------------------------------------------------------------------
28.1.9.1. Initialization Arguments
[change_begin]
An initialization argument controls object creation and initialization. It is
often convenient to use keyword symbols to name initialization arguments, but
the name of an initialization argument can be any symbol, including nil. An
initialization argument can be used in two ways: to fill a slot with a value or
to provide an argument for an initialization method. A single initialization
argument can be used for both purposes.
An initialization argument list is a list of alternating initialization
argument names and values. Its structure is identical to a property list and
also to the portion of an argument list processed for &key parameters. As in
those lists, if an initialization argument name appears more than once in an
initialization argument list, the leftmost occurrence supplies the value and
the remaining occurrences are ignored. The arguments to make-instance (after
the first argument) form an initialization argument list. Error checking of
initialization argument names is disabled if the keyword argument pair whose
keyword is :allow-other-keys and whose value is non-nil appears in the
initialization argument list.
An initialization argument can be associated with a slot. If the initialization
argument has a value in the initialization argument list, the value is stored
into the slot of the newly created object, overriding any :initform form
associated with the slot. A single initialization argument can initialize more
than one slot. An initialization argument that initializes a shared slot stores
its value into the shared slot, replacing any previous value.
An initialization argument can be associated with a method. When an object is
created and a particular initialization argument is supplied, the generic
functions initialize-instance, shared-initialize, and allocate-instance are
called with that initialization argument's name and value as a keyword argument
pair. If a value for the initialization argument is not supplied in the
initialization argument list, the method's lambda-list supplies a default
value.
Initialization arguments are used in four situations: when making an instance,
when re-initializing an instance, when updating an instance to conform to a
redefined class, and when updating an instance to conform to the definition of
a different class.
Because initialization arguments are used to control the creation and
initialization of an instance of some particular class, we say that an
initialization argument is ``an initialization argument for'' that class.
[change_end]
-------------------------------------------------------------------------------
28.1.9.2. Declaring the Validity of Initialization Arguments
[change_begin]
Initialization arguments are checked for validity in each of the four
situations that use them. An initialization argument may be valid in one
situation and not another. For example, the system-supplied primary method for
make-instance defined for the class standard-class checks the validity of its
initialization arguments and signals an error if an initialization argument is
supplied that is not declared valid in that situation.
There are two means of declaring initialization arguments valid.
* Initialization arguments that fill slots are declared valid by the
:initarg slot option to defclass. The :initarg slot option is inherited
from superclasses. Thus the set of valid initialization arguments that
fill slots for a class is the union of the initialization arguments that
fill slots declared valid by that class and its superclasses.
Initialization arguments that fill slots are valid in all four contexts.
* Initialization arguments that supply arguments to methods are declared
valid by defining those methods. The keyword name of each keyword
parameter specified in the method's lambda-list becomes an initialization
argument for all classes for which the method is applicable. Thus method
inheritance controls the set of valid initialization arguments that supply
arguments to methods. The generic functions for which method definitions
serve to declare initialization arguments valid are as follows:
o Making an instance of a class: allocate-instance,
initialize-instance, and shared-initialize. Initialization arguments
declared valid by these methods are valid when making an instance of
a class.
o Re-initializing an instance: the functions reinitialize-instance and
shared-initialize. Initialization arguments declared valid by these
methods are valid when re-initializing an instance.
o Updating an instance to conform to a redefined class:
update-instance-for-redefined-class and shared-initialize.
Initialization arguments declared valid by these methods are valid
when updating an instance to conform to a redefined class.
o Updating an instance to conform to the definition of a different
class: update-instance-for-different-class and shared-initialize.
Initialization arguments declared valid by these methods are valid
when updating an instance to conform to the definition of a different
class.
The set of valid initialization arguments for a class is the set of valid
initialization arguments that either fill slots or supply arguments to methods,
along with the predefined initialization argument :allow-other-keys. The
default value for :allow-other-keys is nil. The meaning of :allow-other-keys is
the same here as when it is passed to an ordinary function.
[change_end]
-------------------------------------------------------------------------------
28.1.9.3. Defaulting of Initialization Arguments
[change_begin]
A default value form can be supplied for an initialization argument by using
the :default-initargs class option. If an initialization argument is declared
valid by some particular class, its default value form might be specified by a
different class. In this case :default-initargs is used to supply a default
value for an inherited initialization argument.
The :default-initargs option is used only to provide default values for
initialization arguments; it does not declare a symbol as a valid
initialization argument name. Furthermore, the :default-initargs option is used
only to provide default values for initialization arguments when making an
instance.
The argument to the :default-initargs class option is a list of alternating
initialization argument names and forms. Each form is the default value form
for the corresponding initialization argument. The default value form of an
initialization argument is used and evaluated only if that initialization
argument does not appear in the arguments to make-instance and is not defaulted
by a more specific class. The default value form is evaluated in the lexical
environment of the defclass form that supplied it; the result is used as the
initialization argument's value.
The initialization arguments supplied to make-instance are combined with
defaulted initialization arguments to produce a defaulted initialization
argument list. A defaulted initialization argument list is a list of
alternating initialization argument names and values in which unsupplied
initialization arguments are defaulted and in which the explicitly supplied
initialization arguments appear earlier in the list than the defaulted
initialization arguments. Defaulted initialization arguments are ordered
according to the order in the class precedence list of the classes that
supplied the default values.
There is a distinction between the purposes of the :default-initargs and the
:initform options with respect to the initialization of slots. The
:default-initargs class option provides a mechanism for the user to give a
default value form for an initialization argument without knowing whether the
initialization argument initializes a slot or is passed to a method. If that
initialization argument is not explicitly supplied in a call to make-instance,
the default value form is used, just as if it had been supplied in the call. In
contrast, the :initform slot option provides a mechanism for the user to give a
default initial value form for a slot. An :initform form is used to initialize
a slot only if no initialization argument associated with that slot is given as
an argument to make-instance or is defaulted by :default-initargs.
The order of evaluation of default value forms for initialization arguments and
the order of evaluation of :initform forms are undefined. If the order of
evaluation matters, use initialize-instance or shared-initialize methods.
[change_end]
-------------------------------------------------------------------------------
28.1.9.4. Rules for Initialization Arguments
[change_begin]
The :initarg slot option may be specified more than once for a given slot. The
following rules specify when initialization arguments may be multiply defined:
* A given initialization argument can be used to initialize more than one
slot if the same initialization argument name appears in more than one
:initarg slot option.
* A given initialization argument name can appear in the lambda-list of
more than one initialization method.
* A given initialization argument name can appear both in an :initarg slot
option and in the lambda-list of an initialization method.
If two or more initialization arguments that initialize the same slot are given
in the arguments to make-instance, the leftmost of these initialization
arguments in the initialization argument list supplies the value, even if the
initialization arguments have different names.
If two or more different initialization arguments that initialize the same slot
have default values and none is given explicitly in the arguments to
make-instance, the initialization argument that appears in a :default-initargs
class option in the most specific of the classes supplies the value. If a
single :default-initargs class option specifies two or more initialization
arguments that initialize the same slot and none is given explicitly in the
arguments to make-instance, the leftmost argument in the :default-initargs
class option supplies the value, and the values of the remaining default value
forms are ignored.
Initialization arguments given explicitly in the arguments to make-instance
appear to the left of defaulted initialization arguments. Suppose that the
classes and supply the values of defaulted initialization arguments for
different slots, and suppose that is more specific than ; then the
defaulted initialization argument whose value is supplied by is to the left
of the defaulted initialization argument whose value is supplied by in the
defaulted initialization argument list. If a single :default-initargs class
option supplies the values of initialization arguments for two different slots,
the initialization argument whose value is specified farther to the left in the
default-initargs class option appears farther to the left in the defaulted
initialization argument list.
If a slot has both an :initform form and an :initarg slot option, and the
initialization argument is defaulted using :default-initargs or is supplied to
make-instance, the captured :initform form is neither used nor evaluated.
The following is an example of the preceding rules:
(defclass q () ((x :initarg a)))
(defclass r (q) ((x :initarg b))
(:default-initargs a 1 b 2))
Defaulted Initialization Contents
Form Argument List of Slot
=======================================================================
(make-instance 'r) (a 1 b 2) 1
(make-instance 'r 'a 3) (a 3 b 2) 3
(make-instance 'r 'b 4) (b 4 a 1) 4
(make-instance 'r 'a 1 'a 2) (a 1 a 2 b 2) 1
=======================================================================
[change_end]
-------------------------------------------------------------------------------
28.1.9.5. Shared-Initialize
[change_begin]
The generic function shared-initialize is used to fill the slots of an instance
using initialization arguments and :initform forms when an instance is created,
when an instance is re-initialized, when an instance is updated to conform to a
redefined class, and when an instance is updated to conform to a different
class. It uses standard method combination. It takes the following arguments:
the instance to be initialized, a specification of a set of names of slots
accessible in that instance, and any number of initialization arguments. The
arguments after the first two must form an initialization argument list.
The second argument to shared-initialize may be one of the following:
* It can be a list of slot names, which specifies the set of those slot
names.
* It can be nil, which specifies the empty set of slot names.
* It can be the symbol t, which specifies the set of all of the slots.
There is a system-supplied primary method for shared-initialize whose first
parameter specializer is the class standard-object. This method behaves as
follows on each slot, whether shared or local:
* If an initialization argument in the initialization argument list
specifies a value for that slot, that value is stored into the slot, even
if a value has already been stored in the slot before the method is run.
The affected slots are independent of which slots are indicated by the
second argument to shared-initialize.
* Any slots indicated by the second argument that are still unbound at this
point are initialized according to their :initform forms. For any such
slot that has an :initform form, that form is evaluated in the lexical
environment of its defining defclass form and the result is stored into
the slot. For example, if a :before method stores a value in the slot, the
:initform form will not be used to supply a value for the slot. If the
second argument specifies a name that does not correspond to any slots
accessible in the instance, the results are unspecified.
* The rules mentioned in section 28.1.9.4 are obeyed.
The generic function shared-initialize is called by the system-supplied primary
methods for the generic functions initialize-instance, reinitialize-instance,
update-instance-for-different-class, and update-instance-for-redefined-class.
Thus methods can be written for shared-initialize to specify actions that
should be taken in all of these contexts.
[change_end]
-------------------------------------------------------------------------------
28.1.9.6. Initialize-Instance
[change_begin]
The generic function initialize-instance is called by make-instance to
initialize a newly created instance. It uses standard method combination.
Methods for initialize-instance can be defined in order to perform any
initialization that cannot be achieved with the simple slot-filling mechanisms.
During initialization, initialize-instance is invoked after the following
actions have been taken:
* The defaulted initialization argument list has been computed by combining
the supplied initialization argument list with any default initialization
arguments for the class.
* The validity of the defaulted initialization argument list has been
checked. If any of the initialization arguments has not been declared
valid, an error is signaled.
* A new instance whose slots are unbound has been created.
The generic function initialize-instance is called with the new instance and
the defaulted initialization arguments. There is a system-supplied primary
method for initialize-instance whose parameter specializer is the class
standard-object. This method calls the generic function shared-initialize to
fill in the slots according to the initialization arguments and the :initform
forms for the slots; the generic function shared-initialize is called with the
following arguments: the instance, t, and the defaulted initialization
arguments.
Note that initialize-instance provides the defaulted initialization argument
list in its call to shared-initialize, so the first step performed by the
system-supplied primary method for shared-initialize takes into account both
the initialization arguments provided in the call to make-instance and the
defaulted initialization argument list.
Methods for initialize-instance can be defined to specify actions to be taken
when an instance is initialized. If only :after methods for initialize-instance
are defined, they will be run after the system-supplied primary method for
initialization and therefore they will not interfere with the default behavior
of initialize-instance.
The Object System provides two functions that are useful in the bodies of
initialize-instance methods. The function slot-boundp returns a boolean value
that indicates whether a specified slot has a value; this provides a mechanism
for writing :after methods for initialize-instance that initialize slots only
if they have not already been initialized. The function slot-makunbound causes
the slot to have no value.
[change_end]
-------------------------------------------------------------------------------
28.1.9.7. Definitions of Make-Instance and Initialize-Instance
[change_begin]
The generic function make-instance behaves as if it were defined as follows,
except that certain optimizations are permitted:
(defmethod make-instance ((class standard-class) &rest initargs)
(setq initargs (default-initargs class initargs))
...
(let ((instance (apply #'allocate-instance class initargs)))
(apply #'initialize-instance instance initargs)
instance))
(defmethod make-instance ((class-name symbol) &rest initargs)
(apply #'make-instance (find-class class-name) initargs))
The elided code in the definition of make-instance checks the supplied
initialization arguments to determine whether an initialization argument was
supplied that neither filled a slot nor supplied an argument to an applicable
method. This check could be implemented using the generic functions
class-prototype, compute-applicable-methods, function-keywords, and
class-slot-initargs. See the third part of the Common Lisp Object System
specification for a description of this initialization argument check. [The
third part has not yet been approved by X3J13 for inclusion in the forthcoming
Common Lisp standard and is not included in this book.-GLS]
The generic function initialize-instance behaves as if it were defined as
follows, except that certain optimizations are permitted:
(defmethod initialize-instance
((instance standard-object) &rest initargs)
(apply #'shared-initialize instance t initargs)))
These procedures can be customized at either the Programmer Interface level,
the meta-object level, or both.
Customizing at the Programmer Interface level includes using the :initform,
:initarg, and :default-initargs options to defclass, as well as defining
methods for make-instance and initialize-instance. It is also possible to
define methods for shared-initialize, which would be invoked by the generic
functions reinitialize-instance, update-instance-for-redefined-class,
update-instance-for-different-class, and initialize-instance. The meta-object
level supports additional customization by allowing methods to be defined on
make-instance, default-initargs, and allocate-instance. Parts 2 and 3 of the
Common Lisp Object System specification document each of these generic
functions and the system-supplied primary methods. [The third part has not yet
been approved by X3J13 for inclusion in the forthcoming Common Lisp standard
and is not included in this book.-GLS]
Implementations are permitted to make certain optimizations to
initialize-instance and shared-initialize. The description of shared-initialize
in section 28.2 mentions the possible optimizations.
Because of optimization, the check for valid initialization arguments might not
be implemented using the generic functions class-prototype,
compute-applicable-methods, function-keywords, and class-slot-initargs. In
addition, methods for the generic function default-initargs and the
system-supplied primary methods for allocate-instance, initialize-instance, and
shared-initialize might not be called on every call to make-instance or might
not receive exactly the arguments that would be expected.
[change_end]
-------------------------------------------------------------------------------
28.1.10. Redefining Classes
[change_begin]
A class that is an instance of standard-class can be redefined if the new class
will also be an instance of standard-class. Redefining a class modifies the
existing class object to reflect the new class definition; it does not create a
new class object for the class. Any method object created by a :reader,
:writer, or :accessor option specified by the old defclass form is removed from
the corresponding generic function. Methods specified by the new defclass form
are added.
When the class C is redefined, changes are propagated to its instances and to
instances of any of its subclasses. Updating such an instance occurs at an
implementation-dependent time, but no later than the next time a slot of that
instance is read or written. Updating an instance does not change its identity
as defined by the eq function. The updating process may change the slots of
that particular instance, but it does not create a new instance. Whether
updating an instance consumes storage is implementation-dependent.
Note that redefining a class may cause slots to be added or deleted. If a class
is redefined in a way that changes the set of local slots accessible in
instances, the instances will be updated. It is implementation-dependent
whether instances are updated if a class is redefined in a way that does not
change the set of local slots accessible in instances.
The value of a slot that is specified as shared both in the old class and in
the new class is retained. If such a shared slot was unbound in the old class,
it will be unbound in the new class. Slots that were local in the old class and
that are shared in the new class are initialized. Newly added shared slots are
initialized.
Each newly added shared slot is set to the result of evaluating the captured
:initform form for the slot that was specified in the defclass form for the new
class. If there is no :initform form, the slot is unbound.
If a class is redefined in such a way that the set of local slots accessible in
an instance of the class is changed, a two-step process of updating the
instances of the class takes place. The process may be explicitly started by
invoking the generic function make-instances-obsolete. This two-step process
can happen in other circumstances in some implementations. For example, in some
implementations this two-step process will be triggered if the order of slots
in storage is changed.
The first step modifies the structure of the instance by adding new local slots
and discarding local slots that are not defined in the new version of the
class. The second step initializes the newly added local slots and performs any
other user-defined actions. These steps are further specified in the next two
sections.
[change_end]
-------------------------------------------------------------------------------
* Modifying the Structure of Instances
* Initializing Newly Added Local Slots
* Customizing Class Redefinition
* Extensions
-------------------------------------------------------------------------------
28.1.10.1. Modifying the Structure of Instances
[change_begin]
The first step modifies the structure of instances of the redefined class to
conform to its new class definition. Local slots specified by the new class
definition that are not specified as either local or shared by the old class
are added, and slots not specified as either local or shared by the new class
definition that are specified as local by the old class are discarded. The
names of these added and discarded slots are passed as arguments to
update-instance-for-redefined-class as described in the next section.
The values of local slots specified by both the new and old classes are
retained. If such a local slot was unbound, it remains unbound.
The value of a slot that is specified as shared in the old class and as local
in the new class is retained. If such a shared slot was unbound, the local slot
will be unbound.
[change_end]
-------------------------------------------------------------------------------
28.1.10.2. Initializing Newly Added Local Slots
[change_begin]
The second step initializes the newly added local slots and performs any other
user-defined actions. This step is implemented by the generic function
update-instance-for-redefined-class, which is called after completion of the
first step of modifying the structure of the instance.
The generic function update-instance-for-redefined-class takes four required
arguments: the instance being updated after it has undergone the first step, a
list of the names of local slots that were added, a list of the names of local
slots that were discarded, and a property list containing the slot names and
values of slots that were discarded and had values. Included among the
discarded slots are slots that were local in the old class and that are shared
in the new class.
The generic function update-instance-for-redefined-class also takes any number
of initialization arguments. When it is called by the system to update an
instance whose class has been redefined, no initialization arguments are
provided.
There is a system-supplied primary method for the generic function
update-instance-for-redefined-class whose parameter specializer for its
instance argument is the class standard-object. First this method checks the
validity of initialization arguments and signals an error if an initialization
argument is supplied that is not declared valid (see section 28.1.9.2.) Then it
calls the generic function shared-initialize with the following arguments: the
instance, the list of names of the newly added slots, and the initialization
arguments it received.
[change_end]
-------------------------------------------------------------------------------
28.1.10.3. Customizing Class Redefinition
[change_begin]
Methods for update-instance-for-redefined-class may be defined to specify
actions to be taken when an instance is updated. If only :after methods for
update-instance-for-redefined-class are defined, they will be run after the
system-supplied primary method for initialization and therefore will not
interfere with the default behavior of update-instance-for-redefined-class.
Because no initialization arguments are passed to
update-instance-for-redefined-class when it is called by the system, the
:initform forms for slots that are filled by :before methods for
update-instance-for-redefined-class will not be evaluated by shared-initialize.
Methods for shared-initialize may be defined to customize class redefinition
(see section 28.1.9.5).
[change_end]
-------------------------------------------------------------------------------
28.1.10.4. Extensions
[change_begin]
There are two allowed extensions to class redefinition:
* The Object System may be extended to permit the new class to be an
instance of a metaclass other than the metaclass of the old class.
* The Object System may be extended to support an updating process when
either the old or the new class is an instance of a class other than
standard-class that is not a built-in class.
[change_end]
-------------------------------------------------------------------------------
28.1.11. Changing the Class of an Instance
[change_begin]
The function change-class can be used to change the class of an instance from
its current class, , to a different class, ; it changes the structure of
the instance to conform to the definition of the class .
Note that changing the class of an instance may cause slots to be added or
deleted.
When change-class is invoked on an instance, a two-step updating process takes
place. The first step modifies the structure of the instance by adding new
local slots and discarding local slots that are not specified in the new
version of the instance. The second step initializes the newly added local
slots and performs any other user-defined actions. These steps are further
described in the following two sections.
[change_end]
-------------------------------------------------------------------------------
* Modifying the Structure of an Instance
* Initializing Newly Added Local Slots
* Customizing the Change of Class of an Instance
-------------------------------------------------------------------------------
28.1.11.1. Modifying the Structure of an Instance
[change_begin]
In order to make an instance conform to the class , local slots specified by
the class that are not specified by the class are added, and local slots
not specified by the class that are specified by the class are discarded.
The values of local slots specified by both the class and the class are
retained. If such a local slot was unbound, it remains unbound.
The values of slots specified as shared in the class and as local in the
class are retained.
This first step of the update does not affect the values of any shared slots.
[change_end]
-------------------------------------------------------------------------------
28.1.11.2. Initializing Newly Added Local Slots
[change_begin]
The second step of the update initializes the newly added slots and performs
any other user-defined actions. This step is implemented by the generic
function update-instance-for-different-class. The generic function
update-instance-for-different-class is invoked by change-class after the first
step of the update has been completed.
The generic function update-instance-for-different-class is invoked on two
arguments computed by change-class. The first argument passed is a copy of the
instance being updated and is an instance of the class ; this copy has
dynamic extent within the generic function change-class. The second argument is
the instance as updated so far by change-class and is an instance of the class
.
The generic function update-instance-for-different-class also takes any number
of initialization arguments. When it is called by change-class, no
initialization arguments are provided.
There is a system-supplied primary method for the generic function
update-instance-for-different-class that has two parameter specializers, each
of which is the class standard-object. First this method checks the validity of
initialization arguments and signals an error if an initialization argument is
supplied that is not declared valid (see section 28.1.9.2). Then it calls the
generic function shared-initialize with the following arguments: the instance,
a list of names of the newly added slots, and the initialization arguments it
received.
[change_end]
-------------------------------------------------------------------------------
28.1.11.3. Customizing the Change of Class of an Instance
[change_begin]
Methods for update-instance-for-different-class may be defined to specify
actions to be taken when an instance is updated. If only :after methods for
update-instance-for-different-class are defined, they will be run after the
system-supplied primary method for initialization and will not interfere with
the default behavior of update-instance-for-different-class. Because no
initialization arguments are passed to update-instance-for-different-class when
it is called by change-class, the :initform forms for slots that are filled by
:before methods for update-instance-for-different-class will not be evaluated
by shared-initialize.
Methods for shared-initialize may be defined to customize class redefinition
(see section 28.1.9.5).
[change_end]
-------------------------------------------------------------------------------
28.1.12. Reinitializing an Instance
[change_begin]
The generic function reinitialize-instance may be used to change the values of
slots according to initialization arguments.
The process of reinitialization changes the values of some slots and performs
any user-defined actions.
Reinitialization does not modify the structure of an instance to add or delete
slots, and it does not use any :initform forms to initialize slots.
The generic function reinitialize-instance may be called directly. It takes one
required argument, the instance. It also takes any number of initialization
arguments to be used by methods for reinitialize-instance or for
shared-initialize. The arguments after the required instance must form an
initialization argument list.
There is a system-supplied primary method for reinitialize-instance whose
parameter specializer is the class standard-object. First this method checks
the validity of initialization arguments and signals an error if an
initialization argument is supplied that is not declared valid (see section
28.1.9.2). Then it calls the generic function shared-initialize with the
following arguments: the instance, nil, and the initialization arguments it
received.
[change_end]
-------------------------------------------------------------------------------
* Customizing Reinitialization
-------------------------------------------------------------------------------
28.1.12.1. Customizing Reinitialization
[change_begin]
Methods for the generic function reinitialize-instance may be defined to
specify actions to be taken when an instance is updated. If only :after methods
for reinitialize-instance are defined, they will be run after the
system-supplied primary method for initialization and therefore will not
interfere with the default behavior of reinitialize-instance.
Methods for shared-initialize may be defined to customize class redefinition
(see section 28.1.9.5).
[change_end]
-------------------------------------------------------------------------------
28.2. Functions in the Programmer Interface
[change_begin]
This section describes the functions, macros, special forms, and generic
functions provided by the Common Lisp Object System Programmer Interface. The
Programmer Interface comprises the functions and macros that are sufficient for
writing most object-oriented programs.
This section is reference material that requires an understanding of the basic
concepts of the Common Lisp Object System. The functions are arranged in
alphabetical order for convenient reference.
The description of each function, macro, special form, and generic function
includes its purpose, its syntax, the semantics of its arguments and returned
values, and often an example and cross-references to related functions.
The syntax description for a function, macro, or special form describes its
parameters. The description of a generic function includes descriptions of the
methods that are defined on that generic function by the Common Lisp Object
System. A method signature is used to describe the parameters and parameter
specializers for each method.
The following is an example of the format for the syntax description of a
generic function with the method signature for one primary method:
[Generic function]
f x y &optional z &key :k
[Primary method]
f (x class) (y t) &optional z &key :k
This description indicates that the generic function f has two required
parameters, x and y. In addition, there is an optional parameter z and a
keyword parameter :k.
The method signature indicates that this method on the generic function f has
two required parameters, x, which must be an instance of the class class, and
y, which can be any object. In addition, there is an optional parameter z and a
keyword parameter :k. The signature also indicates that this method on f is a
primary method and has no qualifiers.
The syntax description for a generic function describes the lambda-list of the
generic function itself, while the method signatures describe the lambda-lists
of the defined methods.
The generic functions described in this book are all standard generic
functions. They all use standard method combination.
Any implementation of the Common Lisp Object System is allowed to provide
additional methods on the generic functions described here.
It is useful to categorize the functions and macros according to their role in
this standard:
* Tools used for simple object-oriented programming
These tools allow for defining new classes, methods, and generic functions
and for making instances. Some tools used within method bodies are also
listed here. Some of the macros listed here have a corresponding function
that performs the same task at a lower level of abstraction.
call-next-method initialize-instance
change-class make-instance
defclass next-method-p
defgeneric slot-boundp
defmethod slot-value
generic-flet with-accessors
generic-function with-added-methods
generic-labels with-slots
* Functions underlying the commonly used macros
add-method reinitialize-instance
class-name remove-method
compute-applicable-methods shared-initialize
ensure-generic-function slot-exists-p
find-class slot-makunbound
find-method slot-missing
function-keywords slot-unbound
make-instances-obsolete update-instance-for-different-class
no-applicable-method update-instance-for-redefined-class
no-next-method
* Tools for declarative method combination
call-method method-combination-error
define-method-combination method-qualifiers
invalid-method-error
* General Common Lisp support tools
class-of print-object
documentation symbol-macrolet
[Note that describe appeared in this list in the original CLOS proposal
[5,7], but X3J13 voted in March 1989 (DESCRIBE-UNDERSPECIFIED) not to
make describe a generic function after all (see describe-object).-GLS]
[At this point the original CLOS report contained a description of the [[ and
]] notation; that description is omitted here. I have adopted the notation for
use throughout this book. It is described in section 1.2.5.-GLS]
[Generic function]
add-method generic-function method
[Primary method]
add-method
(generic-function standard-generic-function) (method method)
The generic function add-method adds a method to a generic function. It
destructively modifies the generic function and returns the modified generic
function as its result.
The generic-function argument is a generic function object.
The method argument is a method object. The lambda-list of the method function
must be congruent with the lambda-list of the generic function, or an error is
signaled.
The modified generic function is returned. The result of add-method is eq to
the generic-function argument.
If the given method agrees with an existing method of the generic function on
parameter specializers and qualifiers, the existing method is replaced. See
section 28.1.6.3 for a definition of agreement in this context.
If the method object is a method object of another generic function, an error
is signaled.
See section 28.1.6.3 as well as defmethod, defgeneric, find-method, and
remove-method.
[Macro]
call-method method next-method-list
The macro call-method is used in method combination. This macro hides the
implementation-dependent details of how methods are called. It can be used only
within an effective method form, for the name call-method is defined only
within the lexical scope of such a form.
The macro call-method invokes the specified method, supplying it with arguments
and with definitions for call-next-method and for next-method-p. The arguments
are the arguments that were supplied to the effective method form containing
the invocation of call-method. The definitions of call-next-method and
next-method-p rely on the list of method objects given as the second argument
to call-method.
The call-next-method function available to the method that is the first subform
will call the first method in the list that is the second subform. The
call-next-method function available in that method, in turn, will call the
second method in the list that is the second subform, and so on, until the list
of next methods is exhausted.
The method argument is a method object; the next-method-list argument is a list
of method objects.
A list whose first element is the symbol make-method and whose second element
is a Lisp form can be used instead of a method object as the first subform of
call-method or as an element of the second subform of call-method. Such a list
specifies a method object whose method function has a body that is the given
form.
The result of call-method is the value or values returned by the method
invocation.
See call-next-method, define-method-combination, and next-method-p.
[Function]
call-next-method &rest args
The function call-next-method can be used within the body of a method defined
by a method-defining form to call the next method.
The function call-next-method returns the value or values returned by the
method it calls. If there is no next method, the generic function
no-next-method is called.
The type of method combination used determines which methods can invoke
call-next-method. The standard method combination type allows call-next-method
to be used within primary methods and :around methods.
The standard method combination type defines the next method according to the
following rules:
* If call-next-method is used in an :around method, the next method is the
next most specific :around method, if one is applicable.
* If there are no :around methods at all or if call-next-method is called
by the least specific :around method, other methods are called as follows:
o All the :before methods are called, in most-specific-first order.
The function call-next-method cannot be used in :before methods.
o The most specific primary method is called. Inside the body of a
primary method, call-next-method may be used to pass control to the
next most specific primary method. The generic function
no-next-method is called if call-next-method is used and there are no
more primary methods.
o All the :after methods are called in most-specific-last order. The
function call-next-method cannot be used in :after methods.
For further discussion of the use of call-next-method, see sections 28.1.7.2
and 28.1.7.4.
When call-next-method is called with no arguments, it passes the current
method's original arguments to the next method. Neither argument defaulting,
nor using setq, nor rebinding variables with the same names as parameters of
the method affects the values call-next-method passes to the method it calls.
When call-next-method is called with arguments, the next method is called with
those arguments. When providing arguments to call-next-method, the following
rule must be satisfied or an error is signaled: The ordered set of methods
applicable for a changed set of arguments for call-next-method must be the same
as the ordered set of applicable methods for the original arguments to the
generic function. Optimizations of the error checking are possible, but they
must not change the semantics of call-next-method.
If call-next-method is called with arguments but omits optional arguments, the
next method called defaults those arguments.
The function call-next-method returns the value or values returned by the
method it calls.
Further computation is possible after call-next-method returns.
The definition of the function call-next-method has lexical scope (for it is
defined only within the body of a method defined by a method-defining form) and
indefinite extent.
For generic functions using a type of method combination defined by the short
form of define-method-combination, call-next-method can be used in :around
methods only.
The function next-method-p can be used to test whether or not there is a next
method.
If call-next-method is used in methods that do not support it, an error is
signaled.
See sections 28.1.7, 28.1.7.2, and 28.1.7.4 as well as the functions
define-method-combination, next-method-p, and no-next-method.
[Generic function]
change-class instance new-class
[Primary method]
change-class (instance standard-object)
(new-class standard-class)
change-class (instance t)
(new-class symbol)
The generic function change-class changes the class of an instance to a new
class. It destructively modifies and returns the instance.
If in the old class there is any slot of the same name as a local slot in the
new class, the value of that slot is retained. This means that if the slot has
a value, the value returned by slot-value after change-class is invoked is eql
to the value returned by slot-value before change-class is invoked. Similarly,
if the slot was unbound, it remains unbound. The other slots are initialized as
described in section 28.1.11.
The instance argument is a Lisp object.
The new-class argument is a class object or a symbol that names a class.
If the second of the preceding methods is selected, that method invokes
change-class on instance and (find-class new-class).
The modified instance is returned. The result of change-class is eq to the
instance argument.
Examples:
(defclass position () ())
(defclass x-y-position (position)
((x :initform 0 :initarg :x)
(y :initform 0 :initarg :y)))
(defclass rho-theta-position (position)
((rho :initform 0)
(theta :initform 0)))
(defmethod update-instance-for-different-class :before
((old x-y-position)
(new rho-theta-position)
&key)
;; Copy the position information from old to new to make new
;; be a rho-theta-position at the same position as old.
(let ((x (slot-value old 'x))
(y (slot-value old 'y)))
(setf (slot-value new 'rho) (sqrt (+ (* x x) (* y y)))
(slot-value new 'theta) (atan y x))))
;;; At this point an instance of the class x-y-position can be
;;; changed to be an instance of the class rho-theta-position
;;; using change-class:
(setq p1 (make-instance 'x-y-position :x 2 :y 0))
(change-class p1 'rho-theta-position)
;;; The result is that the instance bound to p1 is now
;;; an instance of the class rho-theta-position.
;;; The update-instance-for-different-class method
;;; performed the initialization of the rho and theta
;;; slots based on the values of the x and y slots,
;;; which were maintained by the old instance.
After completing all other actions, change-class invokes the generic function
update-instance-for-different-class. The generic function
update-instance-for-different-class can be used to assign values to slots in
the transformed instance.
The generic function change-class has several semantic difficulties. First, it
performs a destructive operation that can be invoked within a method on an
instance that was used to select that method. When multiple methods are
involved because methods are being combined, the methods currently executing or
about to be executed may no longer be applicable. Second, some implementations
might use compiler optimizations of slot access, and when the class of an
instance is changed the assumptions the compiler made might be violated. This
implies that a programmer must not use change-class inside a method if any
methods for that generic function access any slots, or the results are
undefined.
See section 28.1.11 as well as update-instance-for-different-class.
[Generic function]
class-name class
[Primary method]
class-name (class class)
The generic function class-name takes a class object and returns its name. The
class argument is a class object. The new-value argument is any object. The
name of the given class is returned.
The name of an anonymous class is nil.
If S is a symbol such that S =(class-name C) and C = (find-class S), then S is
the proper name of C (see section 28.1.2).
See also section 28.1.2 and find-class.
[Generic function]
(setf class-name) new-value class
[Primary method]
(setf class-name) new-value (class class)
The generic function (setf class-name) takes a class object and sets its name.
The class argument is a class object. The new-value argument is any object.
[Function]
class-of object
The function class-of returns the class of which the given object is an
instance. The argument to class-of may be any Common Lisp object. The function
class-of returns the class of which the argument is an instance.
[Function]
compute-applicable-methods generic-function function-arguments
Given a generic function and a set of arguments, the function
compute-applicable-methods returns the set of methods that are applicable for
those arguments.
The methods are sorted according to precedence order. See section 28.1.7.
The generic-function argument must be a generic function object. The
function-arguments argument is a list of the arguments to that generic
function. The result is a list of the applicable methods in order of
precedence. See section 28.1.7.
[Macro]
defclass class-name ({superclass-name}*)
({slot-specifier}*) [[?class-option]]
class-name ::= symbol
superclass-name ::= symbol
slot-specifier ::= slot-name | (slot-name [[?slot-option]])
slot-name ::= symbol
slot-option ::= {:reader reader-function-name}*
| {:writer writer-function-name}*
| {:accessor reader-function-name}*
| {:allocation allocation-type}*
| {:initarg initarg-name}*
| {:initform form}*
| {:type type-specifier}*
| {:documentation string}*
reader-function-name ::= symbol
writer-function-name ::= function-name/
function-name ::= {symbol | (setf symbol)}
initarg-name ::= symbol
allocation-type ::= :instance | :class
class-option ::= (:default-initargs initarg-list)
| (:documentation string)
| (:metaclass class-name)
initarg-list ::= {initarg-name default-initial-value-form}*
The macro defclass defines a new named class. It returns the new class object
as its result.
The syntax of defclass provides options for specifying initialization arguments
for slots, for specifying default initialization values for slots, and for
requesting that methods on specified generic functions be automatically
generated for reading and writing the values of slots. No reader or writer
functions are defined by default; their generation must be explicitly
requested.
Defining a new class also causes a type of the same name to be defined. The
predicate (typep object class-name) returns true if the class of the given
object is class-name itself or a subclass of the class class-name. A class
object can be used as a type specifier. Thus (typep object class) returns true
if the class of the object is class itself or a subclass of class.
The class-name argument is a non-nil symbol. It becomes the proper name of the
new class. If a class with the same proper name already exists and that class
is an instance of standard-class, and if the defclass form for the definition
of the new class specifies a class of class standard-class, the definition of
the existing class is replaced.
Each superclass-name argument is a non-nil symbol that specifies a direct
superclass of the new class. The new class will inherit slots and methods from
each of its direct superclasses, from their direct superclasses, and so on. See
section 28.1.3 for a discussion of how slots and methods are inherited.
Each slot-specifier argument is the name of the slot or a list consisting of
the slot name followed by zero or more slot options. The slot-name argument is
a symbol that is syntactically valid for use as a variable name. If there are
any duplicate slot names, an error is signaled.
The following slot options are available:
* The :reader slot option specifies that an unqualified method is to be
defined on the generic function named reader-function-name to read the
value of the given slot. The reader-function-name argument is a non-nil
symbol. The :reader slot option may be specified more than once for a
given slot.
* The :writer slot option specifies that an unqualified method is to be
defined on the generic function named writer-function-name to write the
value of the slot. The writer-function-name argument is a function-name.
The :writer slot option may be specified more than once for a given slot.
* The :accessor slot option specifies that an unqualified method is to be
defined on the generic function named reader-function-name to read the
value of the given slot and that an unqualified method is to be defined on
the generic function named (setf reader-function-name) to be used with
setf to modify the value of the slot. The reader-function-name argument is
a non-nil symbol. The :accessor slot option may be specified more than
once for a given slot.
* The :allocation slot option is used to specify where storage is to be
allocated for the given slot. Storage for a slot may be located in each
instance or in the class object itself, for example. The value of the
allocation-type argument can be either the keyword :instance or the
keyword :class. The :allocation slot option may be specified at most once
for a given slot. If the :allocation slot option is not specified, the
effect is the same as specifying :allocation :instance.
o If allocation-type is :instance, a local slot of the given name is
allocated in each instance of the class.
o If allocation-type is :class, a shared slot of the given name is
allocated. The value of the slot is shared by all instances of the
class. If a class C defines such a shared slot, any subclass C of C
will share this single slot unless the defclass form for C specifies
a slot of the same name or there is a superclass of C that precedes C
in the class precedence list of C and that defines a slot of the same
name.
* The :initform slot option is used to provide a default initial value form
to be used in the initialization of the slot. The :initform slot option
may be specified at most once for a given slot. This form is evaluated
every time it is used to initialize the slot. The lexical environment in
which this form is evaluated is the lexical environment in which the
defclass form was evaluated. Note that the lexical environment refers both
to variables and to functions. For local slots, the dynamic environment is
the dynamic environment in which make-instance was called; for shared
slots, the dynamic environment is the dynamic environment in which the
defclass form was evaluated. See section 28.1.9.
No implementation is permitted to extend the syntax of defclass to allow
(slot-name form) as an abbreviation for (slot-name :initform form).
* The :initarg slot option declares an initialization argument named
initarg-name and specifies that this initialization argument initializes
the given slot. If the initialization argument has a value in the call to
initialize-instance, the value will be stored into the given slot, and the
slot's :initform slot option, if any, is not evaluated. If none of the
initialization arguments specified for a given slot has a value, the slot
is initialized according to the :initform slot option, if specified. The
:initarg slot option can be specified more than once for a given slot. The
initarg-name argument can be any symbol.
* The :type slot option specifies that the contents of the slot will always
be of the specified data type. It effectively declares the result type of
the reader generic function when applied to an object of this class. The
result of attempting to store in a slot a value that does not satisfy the
type of the slot is undefined. The :type slot option may be specified at
most once for a given slot. The :type slot option is further discussed in
section 28.1.3.2.
* The :documentation slot option provides a documentation string for the
slot.
Each class option is an option that refers to the class as a whole or to all
class slots. The following class options are available:
* The :default-initargs class option is followed by a list of alternating
initialization argument names and default initial value forms. If any of
these initialization arguments does not appear in the initialization
argument list supplied to make-instance, the corresponding default initial
value form is evaluated, and the initialization argument name and the
form's value are added to the end of the initialization argument list
before the instance is created (see section 28.1.9). The default initial
value form is evaluated each time it is used. The lexical environment in
which this form is evaluated is the lexical environment in which the
defclass form was evaluated. The dynamic environment is the dynamic
environment in which make-instance was called. If an initialization
argument name appears more than once in a :default-initargs class option,
an error is signaled. The :default-initargs class option may be specified
at most once.
* The :documentation class option causes a documentation string to be
attached to the class name. The documentation type for this string is
type. The form (documentation class-name 'type) may be used to retrieve
the documentation string. The :documentation class option may be specified
at most once.
* The :metaclass class option is used to specify that instances of the
class being defined are to have a different metaclass than the default
provided by the system (the class standard-class). The class-name argument
is the name of the desired metaclass. The :metaclass class option may be
specified at most once.
The new class object is returned as the result.
If a class with the same proper name already exists and that class is an
instance of standard-class, and if the defclass form for the definition of the
new class specifies a class of class standard-class, the existing class is
redefined, and instances of it (and its subclasses) are updated to the new
definition at the time that they are next accessed (see section 28.1.10).
Note the following rules of defclass for standard classes:
* It is not required that the superclasses of a class be defined before the
defclass form for that class is evaluated.
* All the superclasses of a class must be defined before an instance of the
class can be made.
* A class must be defined before it can be used as a parameter specializer
in a defmethod form.
The Object System may be extended to cover situations where these rules are not
obeyed.
Some slot options are inherited by a class from its superclasses, and some can
be shadowed or altered by providing a local slot description. No class options
except :default-initargs are inherited. For a detailed description of how slots
and slot options are inherited, see section 28.1.3.2.
The options to defclass can be extended. An implementation must signal an error
if it observes a class option or a slot option that is not implemented locally.
It is valid to specify more than one reader, writer, accessor, or
initialization argument for a slot. No other slot option may appear more than
once in a single slot description, or an error is signaled.
If no reader, writer, or accessor is specified for a slot, the slot can be
accessed only by the function slot-value.
See sections 28.1.2, 28.1.3, 28.1.10, 28.1.5, 28.1.9 as well as slot-value,
make-instance, and initialize-instance.
[Macro]
defgeneric function-name lambda-list
[[?option | {method-description}*]]
function-name ::= {symbol | (setf symbol)}
lambda-list ::= ({var}*
[&optional {var | (var)}*]
[&rest var]
[&key {keyword-parameter}* [&allow-other-keys]])
keyword-parameter ::= var | ({var | (keyword var)})
option ::= (:argument-precedence-order {parameter-name}+)
| (declare {declaration}+)
| (:documentation string)
| (:method-combination symbol {arg}*)
| (:generic-function-class class-name)
| (:method-class class-name)
method-description ::= (:method {method-qualifier}*
specialized-lambda-list
[[ {declaration}* | documentation ]]
{form}*)
method-qualifier ::= non-nil-atom
specialized-lambda-list ::=
({var | (var parameter-specializer-name)}*
[&optional {var | (var [initform [supplied-p-parameter]])}*]
[&rest var]
[&key {specialized-keyword-parameter}* [&allow-other-keys]]
[&aux {var | (var [initform])}*])
specialized-keyword-parameter ::=
var | ({var | (keyword var)} [initform [supplied-p-parameter]])
parameter-specializer-name ::= symbol | (eql eql-specializer-form)
The macro defgeneric is used to define a generic function or to specify options
and declarations that pertain to a generic function as a whole.
If (fboundp function-name) is nil, a new generic function is created. If
(fdefinition function-specifier) is a generic function, that generic function
is modified. If function-name/ names a non-generic function, a macro, or a
special form, an error is signaled.
[X3J13 voted in March 1989 (FUNCTION-NAME) to use fdefinition in the previous
paragraph, as shown, rather than symbol-function, as it appeared in the
original report on CLOS [5,7]. The vote also changed all occurrences of
function-specifier in the original report to function-name; this change is
reflected here.-GLS]
Each method-description defines a method on the generic function. The
lambda-list of each method must be congruent with the lambda-list specified by
the lambda-list option. If this condition does not hold, an error is signaled.
See section 28.1.6.4 for a definition of congruence in this context.
The macro defgeneric returns the generic function object as its result.
The function-name argument is a non-nil symbol or a list of the form (setf
symbol).
The lambda-list argument is an ordinary function lambda-list with the following
exceptions:
* The use of &aux is not allowed.
* Optional and keyword arguments may not have default initial value forms
nor use supplied-p parameters. The generic function passes to the method
all the argument values passed to it, and only those; default values are
not supported. Note that optional and keyword arguments in method
definitions, however, can have default initial value forms and can use
supplied-p parameters.
The following options are provided. A given option may occur only once, or an
error is signaled.
* The :argument-precedence-order option is used to specify the order in
which the required arguments in a call to the generic function are tested
for specificity when selecting a particular method. Each required
argument, as specified in the lambda-list argument, must be included
exactly once as a parameter-name so that the full and unambiguous
precedence order is supplied. If this condition is not met, an error is
signaled.
* The declare option is used to specify declarations that pertain to the
generic function. The following standard Common Lisp declaration is
allowed:
o An optimize declaration specifies whether method selection should be
optimized for speed or space, but it has no effect on methods. To
control how a method is optimized, an optimize declaration must be
placed directly in the defmethod form or method description. The
optimization qualities speed and space are the only qualities this
standard requires, but an implementation can extend the Common Lisp
Object System to recognize other qualities. A simple implementation
that has only one method selection technique and ignores the optimize
declaration is valid.
The special, ftype, function, inline, notinline, and declaration
declarations are not permitted. Individual implementations can extend the
declare option to support additional declarations. If an implementation
notices a declaration that it does not support and that has not been
proclaimed as a non-standard declaration name in a declaration
proclamation, it should issue a warning.
* The :documentation argument associates a documentation string with the
generic function. The documentation type for this string is function. The
form (documentation function-name/ 'function) may be used to retrieve this
string.
* The :generic-function-class option may be used to specify that the
generic function is to have a different class than the default provided by
the system (the class standard-generic-function). The class-name argument
is the name of a class that can be the class of a generic function. If
function-name specifies an existing generic function that has a different
value for the :generic-function-class argument and the new generic
function class is compatible with the old, change-class is called to
change the class of the generic function; otherwise an error is signaled.
* The :method-class option is used to specify that all methods on this
generic function are to have a different class from the default provided
by the system (the class standard-method). The class-name argument is the
name of a class that is capable of being the class of a method.
* The :method-combination option is followed by a symbol that names a type
of method combination. The arguments (if any) that follow that symbol
depend on the type of method combination. Note that the standard method
combination type does not support any arguments. However, all types of
method combination defined by the short form of define-method-combination
accept an optional argument named order, defaulting to
:most-specific-first, where a value of :most-specific-last reverses the
order of the primary methods without affecting the order of the auxiliary
methods.
The method-description arguments define methods that will be associated with
the generic function. The method-qualifier and specialized-lambda-list
arguments in a method description are the same as for defmethod.
The form arguments specify the method body. The body of the method is enclosed
in an implicit block. If function-name is a symbol, this block bears the same
name as the generic function. If function-name is a list of the form (setf
symbol), the name of the block is symbol.
The generic function object is returned as the result.
The effect of the defgeneric macro is as if the following three steps were
performed: first, methods defined by previous defgeneric forms are removed;
second, ensure-generic-function is called; and finally, methods specified by
the current defgeneric form are added to the generic function.
If no method descriptions are specified and a generic function of the same name
does not already exist, a generic function with no methods is created.
The lambda-list argument of defgeneric specifies the shape of lambda-lists for
the methods on this generic function. All methods on the resulting generic
function must have lambda-lists that are congruent with this shape. If a
defgeneric form is evaluated and some methods for that generic function have
lambda-lists that are not congruent with that given in the defgeneric form, an
error is signaled. For further details on method congruence, see section
28.1.6.4.
Implementations can extend defgeneric to include other options. It is required
that an implementation signal an error if it observes an option that is not
implemented locally.
See section 28.1.6.4 as well as defmethod, ensure-generic-function, and
generic-function.
[Macro]
define-method-combination name [[?short-form-option]]
define-method-combination name lambda-list
({method-group-specifier}*)
[(:arguments . lambda-list)]
[(:generic-function generic-fn-symbol)]
[[{declaration}* | doc-string]]
{form}*
short-form-option ::= :documentation string
| :identity-with-one-argument boolean
| :operator operator
method-group-specifier ::= (variable {{qualifier-pattern}+ | predicate}
[[?long-form-option]])
long-form-option ::= :description format-string
| :order order
| :required boolean
The macro define-method-combination is used to define new types of method
combination.
There are two forms of define-method-combination. The short form is a simple
facility for the cases that are expected to be most commonly needed. The long
form is more powerful but more verbose. It resembles defmacro in that the body
is an expression, usually using backquote, that computes a Lisp form. Thus
arbitrary control structures can be implemented. The long form also allows
arbitrary processing of method qualifiers.
In both the short and long forms, name is a symbol. By convention, non-keyword,
non-nil symbols are usually used.
The short-form syntax of define-method-combination is recognized when the
second subform is a non-nil symbol or is not present. When the short form is
used, name is defined as a type of method combination that produces a Lisp form
(operator method-call method-call ... ). The operator is a symbol that can be
the name of a function, macro, or special form. The operator can be specified
by a keyword option; it defaults to name.
Keyword options for the short form are the following:
* The :documentation option is used to document the method-combination
type.
* The :identity-with-one-argument option enables an optimization when
boolean is true (the default is false). If there is exactly one applicable
method and it is a primary method, that method serves as the effective
method and operator is not called. This optimization avoids the need to
create a new effective method and avoids the overhead of a function call.
This option is designed to be used with operators such as progn, and, +,
and max.
* The :operator option specifies the name of the operator. The operator
argument is a symbol that can be the name of a function, macro, or special
form. By convention, name and operator are often the same symbol. This is
the default, but it is not required.
None of the subforms is evaluated.
These types of method combination require exactly one qualifier per method. An
error is signaled if there are applicable methods with no qualifiers or with
qualifiers that are not supported by the method combination type.
A method combination procedure defined in this way recognizes two roles for
methods. A method whose one qualifier is the symbol naming this type of method
combination is defined to be a primary method. At least one primary method must
be applicable or an error is signaled. A method with :around as its one
qualifier is an auxiliary method that behaves the same as an :around method in
standard method combination. The function call-next-method can be used only in
:around methods; it cannot be used in primary methods defined by the short form
of the define-method-combination macro.
A method combination procedure defined in this way accepts an optional argument
named order, which defaults to :most-specific-first. A value of
:most-specific-last reverses the order of the primary methods without affecting
the order of the auxiliary methods.
The short form automatically includes error checking and support for :around
methods.
For a discussion of built-in method combination types, see section 28.1.7.4.
The long-form syntax of define-method-combination is recognized when the second
subform is a list.
The lambda-list argument is an ordinary lambda-list. It receives any arguments
provided after the name of the method combination type in the
:method-combination option to defgeneric.
A list of method group specifiers follows. Each specifier selects a subset of
the applicable methods to play a particular role, either by matching their
qualifiers against some patterns or by testing their qualifiers with a
predicate. These method group specifiers define all method qualifiers that can
be used with this type of method combination. If an applicable method does not
fall into any method group, the system signals the error that the method is
invalid for the kind of method combination in use.
Each method group specifier names a variable. During the execution of the forms
in the body of define-method-combination, this variable is bound to a list of
the methods in the method group. The methods in this list occur in
most-specific-first order.
A qualifier pattern is a list or the symbol *. A method matches a qualifier
pattern if the method's list of qualifiers is equal to the qualifier pattern
(except that the symbol * in a qualifier pattern matches anything). Thus a
qualifier pattern can be one of the following: the empty list (), which matches
unqualified methods; the symbol *, which matches all methods; a true list,
which matches methods with the same number of qualifiers as the length of the
list when each qualifier matches the corresponding list element; or a dotted
list that ends in the symbol * (the * matches any number of additional
qualifiers).
Each applicable method is tested against the qualifier patterns and predicates
in left-to-right order. As soon as a qualifier pattern matches or a predicate
returns true, the method becomes a member of the corresponding method group and
no further tests are made. Thus if a method could be a member of more than one
method group, it joins only the first such group. If a method group has more
than one qualifier pattern, a method need only satisfy one of the qualifier
patterns to be a member of the group.
The name of a predicate function can appear instead of qualifier patterns in a
method group specifier. The predicate is called for each method that has not
been assigned to an earlier method group; it is called with one argument, the
method's qualifier list. The predicate should return true if the method is to
be a member of the method group. A predicate can be distinguished from a
qualifier pattern because it is a symbol other than nil or *.
If there is an applicable method whose qualifiers are not valid for the method
combination type, the function invalid-method-error is called.
Method group specifiers can have keyword options following the qualifier
patterns or predicate. Keyword options can be distinguished from additional
qualifier patterns because they are neither lists nor the symbol *. The keyword
options are:
* The :description option is used to provide a description of the role of
methods in the method group. Programming environment tools use (apply
#'format stream format-string (method-qualifiers method)) to print this
description, which is expected to be concise. This keyword option allows
the description of a method qualifier to be defined in the same module
that defines the meaning of the method qualifier. In most cases,
format-string will not contain any format directives, but they are
available for generality. If :description is not specified, a default
description is generated based on the variable name and the qualifier
patterns and on whether this method group includes the unqualified
methods. The argument format-string is not evaluated.
* The :order option specifies the order of methods. The order argument is a
form that evaluates to :most-specific-first or :most-specific-last. If it
evaluates to any other value, an error is signaled. This keyword option is
a convenience and does not add any expressive power. If :order is not
specified, it defaults to :most-specific-first.
* The :required option specifies whether at least one method in this method
group is required. If the boolean argument is non-nil and the method group
is empty (that is, no applicable methods match the qualifier patterns or
satisfy the predicate), an error is signaled. This keyword option is a
convenience and does not add any expressive power. If :required is not
specified, it defaults to nil. The boolean argument is not evaluated.
The use of method group specifiers provides a convenient syntax to select
methods, to divide them among the possible roles, and to perform the necessary
error checking. It is possible to perform further filtering of methods in the
body forms by using normal list-processing operations and the functions
method-qualifiers and invalid-method-error. It is permissible to use setq on
the variables named in the method group specifiers and to bind additional
variables. It is also possible to bypass the method group specifier mechanism
and do everything in the body forms. This is accomplished by writing a single
method group with * as its only qualifier pattern; the variable is then bound
to a list of all of the applicable methods, in most-specific-first order.
The body forms compute and return the Lisp form that specifies how the methods
are combined, that is, the effective method. The effective method uses the
macro call-method. The definition of this macro has lexical scope and is
available only in an effective method form. Given a method object in one of the
lists produced by the method group specifiers and a list of next methods, the
macro call-method will invoke the method so that call-next-method will have
available the next methods.
When an effective method has no effect other than to call a single method, some
implementations employ an optimization that uses the single method directly as
the effective method, thus avoiding the need to create a new effective method.
This optimization is active when the effective method form consists entirely of
an invocation of the call-method macro whose first subform is a method object
and whose second subform is nil. Each define-method-combination body is
responsible for stripping off redundant invocations of progn, and,
multiple-value-prog1, and the like, if this optimization is desired.
The list (:arguments . lambda-list) can appear before any declaration or
documentation string. This form is useful when the method combination type
performs some specific behavior as part of the combined method and that
behavior needs access to the arguments to the generic function. Each parameter
variable defined by lambda-list is bound to a form that can be inserted into
the effective method. When this form is evaluated during execution of the
effective method, its value is the corresponding argument to the generic
function. If lambda-list is not congruent to the generic function's
lambda-list, additional ignored parameters are automatically inserted until it
is congruent. Thus it is permissible for lambda-list to receive fewer arguments
than the number that the generic function expects.
Erroneous conditions detected by the body should be reported with
method-combination-error or invalid-method-error; these functions add any
necessary contextual information to the error message and will signal the
appropriate error.
The body forms are evaluated inside the bindings created by the lambda-list and
method group specifiers. Declarations at the head of the body are positioned
directly inside bindings created by the lambda-list and outside the bindings of
the method group variables. Thus method group variables cannot be declared.
Within the body forms, generic-function-symbol is bound to the generic function
object.
If a doc-string argument is present, it provides the documentation for the
method combination type.
The functions method-combination-error and invalid-method-error can be called
from the body forms or from functions called by the body forms. The actions of
these two functions can depend on implementation-dependent dynamic variables
automatically bound before the generic function compute-effective-method is
called.
Note that two methods with identical specializers, but with different
qualifiers, are not ordered by the algorithm described in step 2 of the method
selection and combination process described in section 28.1.7. Normally the two
methods play different roles in the effective method because they have
different qualifiers, and no matter how they are ordered in the result of step
2 the effective method is the same. If the two methods play the same role and
their order matters, an error is signaled. This happens as part of the
qualifier pattern matching in define-method-combination.
The value returned by the define-method-combination macro is the new method
combination object.
Most examples of the long form of define-method-combination also illustrate the
use of the related functions that are provided as part of the declarative
method combination facility.
;;; Examples of the short form of define-method-combination
(define-method-combination and :identity-with-one-argument t)
(defmethod func and ((x class1) y)
...)
;;; The equivalent of this example in the long form is:
(define-method-combination and
(&optional (order ':most-specific-first))
((around (:around))
(primary (and) :order order :required t))
(let ((form (if (rest primary)
`(and ,@(mapcar #'(lambda (method)
`(call-method ,method ()))
primary))
`(call-method ,(first primary) ()))))
(if around
`(call-method ,(first around)
(,@(rest around)
(make-method ,form)))
form)))
;;; Examples of the long form of define-method-combination
;;; The default method-combination technique
(define-method-combination standard ()
((around (:around))
(before (:before))
(primary () :required t)
(after (:after)))
(flet ((call-methods (methods)
(mapcar #'(lambda (method)
`(call-method ,method ()))
methods)))
(let ((form (if (or before after (rest primary))
`(multiple-value-prog1
(progn ,@(call-methods before)
(call-method ,(first primary)
,(rest primary)))
,@(call-methods (reverse after)))
`(call-method ,(first primary) ()))))
(if around
`(call-method ,(first around)
(,@(rest around)
(make-method ,form)))
form))))
;;; A simple way to try several methods until one returns non-nil
(define-method-combination or ()
((methods (or)))
`(or ,@(mapcar #'(lambda (method)
`(call-method ,method ()))
methods)))
;;; A more complete version of the preceding
(define-method-combination or
(&optional (order ':most-specific-first))
((around (:around))
(primary (or)))
;; Process the order argument
(case order
(:most-specific-first)
(:most-specific-last (setq primary (reverse primary)))
(otherwise (method-combination-error
"~S is an invalid order.~@
:most-specific-first and :most-specific-last ~
are the possible values."
order)))
;; Must have a primary method
(unless primary
(method-combination-error "A primary method is required."))
;; Construct the form that calls the primary methods
(let ((form (if (rest primary)
`(or ,@(mapcar #'(lambda (method)
`(call-method ,method ()))
primary))
`(call-method ,(first primary) ()))))
;; Wrap the around methods around that form
(if around
`(call-method ,(first around)
(,@(rest around)
(make-method ,form)))
form)))
;;; The same thing, using the :order and :required keyword options
(define-method-combination or
(&optional (order ':most-specific-first))
((around (:around))
(primary (or) :order order :required t))
(let ((form (if (rest primary)
`(or ,@(mapcar #'(lambda (method)
`(call-method ,method ()))
primary))
`(call-method ,(first primary) ()))))
(if around
`(call-method ,(first around)
(,@(rest around)
(make-method ,form)))
form)))
;;; This short-form call is behaviorally identical to the preceding.
(define-method-combination or :identity-with-one-argument t)
;;; Order methods by positive integer qualifiers; note that :around
;;; methods are disallowed here in order to keep the example small.
(define-method-combination example-method-combination ()
((methods positive-integer-qualifier-p))
`(progn ,@(mapcar #'(lambda (method)
`(call-method ,method ()))
(stable-sort methods #'<
:key #'(lambda (method)
(first (method-qualifiers
method)))))))
(defun positive-integer-qualifier-p (method-qualifiers)
(and (= (length method-qualifiers) 1)
(typep (first method-qualifiers) '(integer 0 *))))
;;; Example of the use of :arguments
(define-method-combination progn-with-lock ()
((methods ()))
(:arguments object)
`(unwind-protect
(progn (lock (object-lock ,object))
,@(mapcar #'(lambda (method)
`(call-method ,method ()))
methods))
(unlock (object-lock ,object))))
The :method-combination option of defgeneric is used to specify that a generic
function should use a particular method combination type. The argument to the
:method-combination option is the name of a method combination type.
See sections 28.1.7 and 28.1.7.4 as well as call-method, method-qualifiers,
method-combination-error, invalid-method-error, and defgeneric.
[Macro]
defmethod function-name {method-qualifier}*
specialized-lambda-list
[[ {declaration}* | doc-string]]
{form}*
function-name ::= {symbol | (setf symbol)}
method-qualifier ::= non-nil-atom
parameter-specializer-name ::= symbol | (eql eql-specializer-form)
The macro defmethod defines a method on a generic function.
If (fboundp function-name) is nil, a generic function is created with default
values for the argument precedence order (each argument is more specific than
the arguments to its right in the argument list), for the generic function
class (the class standard-generic-function), for the method class (the class
standard-method), and for the method combination type (the standard method
combination type). The lambda-list of the generic function is congruent with
the lambda-list of the method being defined; if the defmethod form mentions
keyword arguments, the lambda-list of the generic function will mention &key
(but no keyword arguments). If function-name names a non-generic function, a
macro, or a special form, an error is signaled.
If a generic function is currently named by function-name, where function-name
is a symbol or a list of the form (setf symbol), the lambda-list of the method
must be congruent with the lambda-list of the generic function. If this
condition does not hold, an error is signaled. See section 28.1.6.4 for a
definition of congruence in this context.
The function-name argument is a non-nil symbol or a list of the form (setf
symbol). It names the generic function on which the method is defined.
Each method-qualifier argument is an object that is used by method combination
to identify the given method. A method qualifier is a non-nil atom. The method
combination type may further restrict what a method qualifier may be. The
standard method combination type allows for unqualified methods or methods
whose sole qualifier is the keyword :before, the keyword :after, or the keyword
:around.
A specialized-lambda-list is like an ordinary function lambda-list except that
the name of a required parameter can be replaced by a specialized parameter, a
list of the form (variable-name parameter-specializer-name). Only required
parameters may be specialized. A parameter specializer name is a symbol that
names a class or (eql eql-specializer-form). The parameter specializer name
(eql eql-specializer-form) indicates that the corresponding argument must be
eql to the object that is the value of eql-specializer-form for the method to
be applicable. If no parameter specializer name is specified for a given
required parameter, the parameter specializer defaults to the class named t.
See section 28.1.6.2.
The form arguments specify the method body. The body of the method is enclosed
in an implicit block. If function-name is a symbol, this block bears the same
name as the generic function. If function-name is a list of the form (setf
symbol), the name of the block is symbol.
The result of defmethod is the method object.
The class of the method object that is created is that given by the method
class option of the generic function on which the method is defined.
If the generic function already has a method that agrees with the method being
defined on parameter specializers and qualifiers, defmethod replaces the
existing method with the one now being defined. See section 28.1.6.3 for a
definition of agreement in this context.
The parameter specializers are derived from the parameter specializer names as
described in section 28.1.6.2.
The expansion of the defmethod macro refers to each specialized parameter (see
the ignore declaration specifier), including parameters that have an explicit
parameter specializer name of t. This means that a compiler warning does not
occur if the body of the method does not refer to a specialized parameter. Note
that a parameter that specializes on t is not synonymous with an unspecialized
parameter in this context.
See sections 28.1.6.2, 28.1.6.4, and 28.1.6.3.
[At this point the original CLOS report [5,7] contained a specification for
describe as a generic function. This specification is omitted here because
X3J13 voted in March 1989 (DESCRIBE-UNDERSPECIFIED) not to make describe a
generic function after all (see describe-object).-GLS]
[Generic function]
documentation x &optional doc-type
[Primary method]
documentation (method standard-method) &optional doc-type
documentation (generic-function standard-generic-function)
&optional doc-type
documentation (class standard-class) &optional doc-type
documentation (method-combination method-combination)
&optional doc-type
documentation (slot-description standard-slot-description)
&optional doc-type
documentation (symbol symbol) &optional doc-type
documentation (list list) &optional doc-type
The ordinary function documentation (see section 25.2) is replaced by a generic
function. The generic function documentation returns the documentation string
associated with the given object if it is available; otherwise documentation
returns nil.
The first argument of documentation is a symbol, a function-name list of the
form (setf symbol), a method object, a class object, a generic function object,
a method combination object, or a slot description object. Whether a second
argument should be supplied depends on the type of the first argument.
* If the first argument is a method object, a class object, a generic
function object, a method combination object, or a slot description
object, the second argument must not be supplied, or an error is signaled.
* If the first argument is a symbol or a list of the form (setf symbol),
the second argument must be supplied.
o The forms
(documentation symbol 'function)
and
(documentation '(setf symbol) 'function)
return the documentation string of the function, generic function,
special form, or macro named by the symbol or list.
o The form (documentation symbol 'variable) returns the documentation
string of the special variable or constant named by the symbol.
o The form (documentation symbol 'structure) returns the documentation
string of the defstruct structure named by the symbol.
o The form (documentation symbol 'type) returns the documentation
string of the class object named by the symbol, if there is such a
class. If there is no such class, it returns the documentation string
of the type specifier named by the symbol.
o The form (documentation symbol 'setf) returns the documentation
string of the defsetf or define-setf-method definition associated
with the symbol.
o The form (documentation symbol 'method-combination) returns the
documentation string of the method combination type named by the
symbol.
An implementation may extend the set of symbols that are acceptable as the
second argument. If a symbol is not recognized as an acceptable argument by the
implementation, an error must be signaled.
The documentation string associated with the given object is returned unless
none is available, in which case documentation returns nil.
[Generic function]
(setf documentation) new-value x &optional doc-type
[Primary method]
(setf documentation) new-value
(method standard-method) &optional doc-type
(setf documentation) new-value
(generic-function standard-generic-function) &optional doc-type
(setf documentation) new-value
(class standard-class) &optional doc-type
(setf documentation) new-value
(method-combination method-combination) &optional doc-type
(setf documentation) new-value
(slot-description standard-slot-description) &optional doc-type
(setf documentation) new-value
(symbol symbol) &optional doc-type
(setf documentation) new-value
(list list) &optional doc-type
The generic function (setf documentation) is used to update the documentation.
The first argument of (setf documentation) is the new documentation.
The second argument of documentation is a symbol, a function-name list of the
form (setf symbol), a method object, a class object, a generic function object,
a method combination object, or a slot description object. Whether a third
argument should be supplied depends on the type of the second argument. See
documentation.
[Function]
ensure-generic-function function-name &key
:lambda-list:argument-precedence-order:declare:documentation:generic-function-class:method-combination:method-class:environment
function-name ::= {symbol | (setf symbol)}
The function ensure-generic-function is used to define a globally named generic
function with no methods or to specify or modify options and declarations that
pertain to a globally named generic function as a whole.
If (fboundp function-name) is nil, a new generic function is created. If
(fdefinition function-name) is a non-generic function, a macro, or a special
form, an error is signaled.
[X3J13 voted in March 1989 (FUNCTION-NAME) to use fdefinition in the previous
paragraph, as shown, rather than symbol-function, as it appeared in the
original report on CLOS [5,7]. The vote also changed all occurrences of
function-specifier in the original report to function-name; this change is
reflected here.-GLS]
If function-name specifies a generic function that has a different value for
any of the following arguments, the generic function is modified to have the
new value: :argument-precedence-order, :declare, :documentation,
:method-combination.
If function-name specifies a generic function that has a different value for
the :lambda-list argument, and the new value is congruent with the lambda-lists
of all existing methods or there are no methods, the value is changed;
otherwise an error is signaled.
If function-name specifies a generic function that has a different value for
the :generic-function-class argument and if the new generic function class is
compatible with the old, change-class is called to change the class of the
generic function; otherwise an error is signaled.
If function-name specifies a generic function that has a different
:method-class value, the value is changed but any existing methods are not
changed.
The function-name argument is a symbol or a list of the form (setf symbol).
The keyword arguments correspond to the option arguments of defgeneric, except
that the :method-class and :generic-function-class arguments can be class
objects as well as names.
The :environment argument is the same as the &environment argument to macro
expansion functions. It is typically used to distinguish between compile-time
and run-time environments.
The :method-combination argument is a method combination object.
The generic function object is returned. See defgeneric.
[Function]
find-class symbol &optional errorp environment
The function find-class returns the class object named by the given symbol in
the given environment.
The first argument to find-class is a symbol.
If there is no such class and the errorp argument is not supplied or is
non-nil, find-class signals an error. If there is no such class and the errorp
argument is nil, find-class returns nil. The default value of errorp is t.
The optional environment argument is the same as the &environment argument to
macro expansion functions. It is typically used to distinguish between
compile-time and run-time environments.
The result of find-class is the class object named by the given symbol.
The class associated with a particular symbol can be changed by using setf with
find-class. The results are undefined if the user attempts to change the class
associated with a symbol that is defined as a type specifier in chapter 4. See
section 28.1.4.
[Generic function]
find-method generic-function method-qualifiers specializers &optional errorp
[Primary method]
find-method (generic-function standard-generic-function)
method-qualifiers specializers &optional errorp
The generic function find-method takes a generic function and returns the
method object that agrees on method qualifiers and parameter specializers with
the method-qualifiers and specializers arguments of find-method. See section
28.1.6.3 for a definition of agreement in this context.
The generic-function argument is a generic function.
The method-qualifiers argument is a list of the method qualifiers for the
method. The order of the method qualifiers is significant.
The specializers argument is a list of the parameter specializers for the
method. It must correspond in length to the number of required arguments of the
generic function, or an error is signaled. This means that to obtain the
default method on a given generic function, a list whose elements are the class
named t must be given.
If there is no such method and the errorp argument is not supplied or is
non-nil, find-method signals an error. If there is no such method and the
errorp argument is nil, find-method returns nil. The default value of errorp is
t.
The result of find-method is the method object with the given method qualifiers
and parameter specializers.
See section 28.1.6.3.
[Generic function]
function-keywords method
[Primary method]
function-keywords (method standard-method)
The generic function function-keywords is used to return the keyword parameter
specifiers for a given method.
The method argument is a method object.
The generic function function-keywords returns two values: a list of the
explicitly named keywords and a boolean that states whether &allow-other-keys
had been specified in the method definition.
[Special Form]
generic-flet ({(function-name lambda-list
[[?option | {method-description}* ]])}*)
{form}*
The generic-flet special form is analogous to the flet special form. It
produces new generic functions and establishes new lexical function definition
bindings. Each generic function is created with the set of methods specified by
its method descriptions.
The special form generic-flet is used to define generic functions whose names
are meaningful only locally and to execute a series of forms with these
function definition bindings. Any number of such local generic functions may be
defined.
The names of functions defined by generic-flet have lexical scope; they retain
their local definitions only within the body of the generic-flet. Any
references within the body of the generic-flet to functions whose names are the
same as those defined within the generic-flet are thus references to the local
functions instead of to any global functions of the same names. The scope of
these generic function definition bindings, however, includes only the body of
generic-flet, not the definitions themselves. Within the method bodies, local
function names that match those being defined refer to global functions defined
outside the generic-flet. It is thus not possible to define recursive functions
with generic-flet.
The function-name, lambda-list, option, method-qualifier, and
specialized-lambda-list arguments are the same as for defgeneric.
A generic-flet local method definition is identical in form to the method
definition part of a defmethod.
The body of each method is enclosed in an implicit block. If function-name is a
symbol, this block bears the same name as the generic function. If
function-name is a list of the form (setf symbol), the name of the block is
symbol.
The result returned by generic-flet is the value or values returned by the last
form executed. If no forms are specified, generic-flet returns nil.
See generic-labels, defmethod, defgeneric, and generic-function.
[Macro]
generic-function lambda-list [[?option | {method-description}*]]
option ::= (:argument-precedence-order {parameter-name}+)
| (declare {declaration}+)
| (:documentation string)
| (:method-combination symbol {arg}*)
| (:generic-function-class class-name)
| (:method-class class-name)
method-description ::= (:method {method-qualifier}*
specialized-lambda-list
{declaration | documentation}*
{form}*)
The generic-function macro creates an anonymous generic function. The generic
function is created with the set of methods specified by its method
descriptions.
The option, method-qualifier, and specialized-lambda-list arguments are the
same as for defgeneric.
The generic function object is returned as the result.
If no method descriptions are specified, an anonymous generic function with no
methods is created.
See defgeneric, generic-flet, generic-labels, and defmethod.
[Special Form]
generic-labels ((function-name lambda-list
[[?option | {method-description}*]])}*)
{form}*
The generic-labels special form is analogous to the labels special form. It
produces new generic functions and establishes new lexical function definition
bindings. Each generic function is created with the set of methods specified by
its method descriptions.
The special form generic-labels is used to define generic functions whose names
are meaningful only locally and to execute a series of forms with these
function definition bindings. Any number of such local generic functions may be
defined.
The names of functions defined by generic-labels have lexical scope; they
retain their local definitions only within the body of the generic-labels
construct. Any references within the body of the generic-labels construct to
functions whose names are the same as those defined within the generic-labels
form are thus references to the local functions instead of to any global
functions of the same names. The scope of these generic function definition
bindings includes the method bodies themselves as well as the body of the
generic-labels construct.
The function-name, lambda-list, option, method-qualifier, and
specialized-lambda-list arguments are the same as for defgeneric.
A generic-labels local method definition is identical in form to the method
definition part of a defmethod.
The body of each method is enclosed in an implicit block. If function-name is a
symbol, this block bears the same name as the generic function. If
function-name is a list of the form (setf symbol), the name of the block is
symbol.
The result returned by generic-labels is the value or values returned by the
last form executed. If no forms are specified, generic-labels returns nil.
See generic-flet, defmethod, defgeneric, generic-function.
[Generic function]
initialize-instance instance &rest initargs
[Primary method]
initialize-instance (instance standard-object) &rest initargs
The generic function initialize-instance is called by make-instance to
initialize a newly created instance. The generic function initialize-instance
is called with the new instance and the defaulted initialization arguments.
The system-supplied primary method on initialize-instance initializes the slots
of the instance with values according to the initialization arguments and the
:initform forms of the slots. It does this by calling the generic function
shared-initialize with the following arguments: the instance, t (this indicates
that all slots for which no initialization arguments are provided should be
initialized according to their :initform forms) and the defaulted
initialization arguments.
The instance argument is the object to be initialized.
The initargs argument consists of alternating initialization argument names and
values.
The modified instance is returned as the result.
Programmers can define methods for initialize-instance to specify actions to be
taken when an instance is initialized. If only :after methods are defined, they
will be run after the system-supplied primary method for initialization and
therefore will not interfere with the default behavior of initialize-instance.
See sections 28.1.9, 28.1.9.4, and 28.1.9.2 as well as shared-initialize,
make-instance, slot-boundp, and slot-makunbound.
[Function]
invalid-method-error method format-string &rest args
The function invalid-method-error is used to signal an error when there is an
applicable method whose qualifiers are not valid for the method combination
type. The error message is constructed by using a format string and any
arguments to it. Because an implementation may need to add additional
contextual information to the error message, invalid-method-error should be
called only within the dynamic extent of a method combination function.
The function invalid-method-error is called automatically when a method fails
to satisfy every qualifier pattern and predicate in a define-method-combination
form. A method combination function that imposes additional restrictions should
call invalid-method-error explicitly if it encounters a method it cannot
accept.
The method argument is the invalid method object.
The format-string argument is a control string that can be given to format, and
args are any arguments required by that string.
Whether invalid-method-error returns to its caller or exits via throw is
implementation-dependent.
See define-method-combination.
[Generic function]
make-instance class &rest initargs
[Primary method]
make-instance (class standard-class) &rest initargs
make-instance (class symbol) &rest initargs
The generic function make-instance creates a new instance of the given class.
The generic function make-instance may be used as described in section 28.1.9.
The class argument is a class object or a symbol that names a class. The
remaining arguments form a list of alternating initialization argument names
and values.
If the second of the preceding methods is selected, that method invokes
make-instance on the arguments (find-class class) and initargs.
The initialization arguments are checked within make-instance (see section
28.1.9).
The new instance is returned.
The meta-object protocol can be used to define new methods on make-instance to
replace the object-creation protocol.
See section 28.1.9 as well as defclass, initialize-instance, and class-of.
[Generic function]
make-instances-obsolete class
[Primary method]
make-instances-obsolete (class standard-class)
make-instances-obsolete (class symbol)
The generic function make-instances-obsolete is invoked automatically by the
system when defclass has been used to redefine an existing standard class and
the set of local slots accessible in an instance is changed or the order of
slots in storage is changed. It can also be explicitly invoked by the user.
The function make-instances-obsolete has the effect of initiating the process
of updating the instances of the class. During updating, the generic function
update-instance-for-redefined-class will be invoked.
The class argument is a class object symbol that names the class whose
instances are to be made obsolete.
If the second of the preceding methods is selected, that method invokes
make-instances-obsolete on (find-class class).
The modified class is returned. The result of make-instances-obsolete is eq to
the class argument supplied to the first of the preceding methods.
See section 28.1.10 as well as update-instance-for-redefined-class.
[Function]
method-combination-error format-string &rest args
The function method-combination-error is used to signal an error in method
combination. The error message is constructed by using a format string and any
arguments to it. Because an implementation may need to add additional
contextual information to the error message, method-combination-error should be
called only within the dynamic extent of a method combination function.
The format-string argument is a control string that can be given to format, and
args are any arguments required by that string.
Whether method-combination-error returns to its caller or exits via throw is
implementation-dependent.
See define-method-combination.
[Generic function]
method-qualifiers method
[Primary method]
method-qualifiers (method standard-method)
The generic function method-qualifiers returns a list of the qualifiers of the
given method.
The method argument is a method object.
A list of the qualifiers of the given method is returned.
Example:
(setq methods (remove-duplicates methods
:from-end t
:key #'method-qualifiers
:test #'equal))
See define-method-combination.
[Function]
next-method-p
The locally defined function next-method-p can be used within the body of a
method defined by a method-defining form to determine whether a next method
exists.
The function next-method-p takes no arguments.
The function next-method-p returns true or false.
Like call-next-method, the function next-method-p has lexical scope (for it is
defined only within the body of a method defined by a method-defining form) and
indefinite extent.
See call-next-method.
[Generic function]
no-applicable-method generic-function &rest function-arguments
[Primary method]
no-applicable-method (generic-function t) &rest function-arguments
The generic function no-applicable-method is called when a generic function of
the class standard-generic-function is invoked and no method on that generic
function is applicable. The default method signals an error.
The generic function no-applicable-method is not intended to be called by
programmers. Programmers may write methods for it.
The generic-function argument of no-applicable-method is the generic function
object on which no applicable method was found.
The function-arguments argument is a list of the arguments to that generic
function.
[Generic function]
no-next-method generic-function method &rest args
[Primary method]
no-next-method (generic-function standard-generic-function)
(method standard-method) &rest args
The generic function no-next-method is called by call-next-method when there is
no next method. The system-supplied method on no-next-method signals an error.
The generic function no-next-method is not intended to be called by
programmers. Programmers may write methods for it.
The generic-function argument is the generic function object to which the
method that is the second argument belongs.
The method argument is the method that contains the call to call-next-method
for which there is no next method.
The args argument is a list of the arguments to call-next-method.
See call-next-method.
[Generic function]
print-object object stream
[Primary method]
print-object (object standard-object) stream
The generic function print-object writes the printed representation of an
object to a stream. The function print-object is called by the print system; it
should not be called by the user.
Each implementation must provide a method on the class standard-object and
methods on enough other classes so as to ensure that there is always an
applicable method. Implementations are free to add methods for other classes.
Users can write methods for print-object for their own classes if they do not
wish to inherit an implementation-supplied method.
The first argument is any Lisp object. The second argument is a stream; it
cannot be t or nil.
The function print-object returns its first argument, the object.
Methods on print-object must obey the print control special variables named
*print-xxx* for various xxx. The specific details are the following:
* Each method must implement *print-escape*.
* The *print-pretty* control variable can be ignored by most methods other
than the one for lists.
* The *print-circle* control variable is handled by the printer and can be
ignored by methods.
* The printer takes care of *print-level* automatically, provided that each
method handles exactly one level of structure and calls write (or an
equivalent function) recursively if there are more structural levels. The
printer's decision of whether an object has components (and therefore
should not be printed when the printing depth is not less than
*print-level*) is implementation-dependent. In some implementations its
print-object method is not called; in others the method is called, and the
determination that the object has components is based on what it tries to
write to the stream.
* Methods that produce output of indefinite length must obey
*print-length*, but most methods other than the one for lists can ignore
it.
* The *print-base*, *print-radix*, *print-case*, *print-gensym*, and
*print-array* control variables apply to specific types of objects and are
handled by the methods for those objects.
* X3J13 voted in June 1989 (DATA-IO) to add the following point. All
methods for print-object must obey *print-readably*, which takes
precedence over all other printer control variables. This includes both
user-defined methods and implementation-defined methods.
If these rules are not obeyed, the results are undefined.
In general, the printer and the print-object methods should not rebind the
print control variables as they operate recursively through the structure, but
this is implementation-dependent.
In some implementations the stream argument passed to a print-object method is
not the original stream but is an intermediate stream that implements part of
the printer. Methods should therefore not depend on the identity of this
stream.
All of the existing printing functions (write, prin1, print, princ, pprint,
write-to-string, prin1-to-string, princ-to-string, the ~S and ~A format
operations, and the ~B, ~D, ~E, ~F, ~G, ~$, ~O, ~R, and ~X format operations
when they encounter a non-numeric value) are required to be changed to go
through the print-object generic function. Each implementation is required to
replace its former implementation of printing with one or more print-object
methods. Exactly which classes have methods for print-object is not specified;
it would be valid for an implementation to have one default method that is
inherited by all system-defined classes.
[Generic function]
reinitialize-instance instance &rest initargs
[Primary method]
reinitialize-instance (instance standard-object) &rest initargs
The generic function reinitialize-instance can be used to change the values of
local slots according to initialization arguments. This generic function is
called by the Meta-Object Protocol. It can also be called by users.
The system-supplied primary method for reinitialize-instance checks the
validity of initialization arguments and signals an error if an initialization
argument is supplied that is not declared valid. The method then calls the
generic function shared-initialize with the following arguments: the instance,
nil (which means no slots should be initialized according to their :initform
forms) and the initialization arguments it received.
The instance argument is the object to be initialized.
The initargs argument consists of alternating initialization argument names and
values.
The modified instance is returned as the result.
Initialization arguments are declared valid by using the :initarg option to
defclass, or by defining methods for reinitialize-instance or
shared-initialize. The keyword name of each keyword parameter specifier in the
lambda-list of any method defined on reinitialize-instance or shared-initialize
is declared a valid initialization argument name for all classes for which that
method is applicable.
See sections 28.1.12, 28.1.9.4, 28.1.9.2 as well as initialize-instance,
slot-boundp, update-instance-for-redefined-class,
update-instance-for-different-class, slot-makunbound, and shared-initialize.
[Generic function]
remove-method generic-function method
[Primary method]
remove-method (generic-function standard-generic-function) method
The generic function remove-method removes a method from a generic function. It
destructively modifies the specified generic function and returns the modified
generic function as its result.
The generic-function argument is a generic function object.
The method argument is a method object. The function remove-method does not
signal an error if the method is not one of the methods on the generic
function.
The modified generic function is returned. The result of remove-method is eq to
the generic-function argument.
See find-method.
[Generic function]
shared-initialize instance slot-names &rest initargs
[Primary method]
shared-initialize (instance standard-object)
slot-names &rest initargs
The generic function shared-initialize is used to fill the slots of an instance
using initialization arguments and :initform forms. It is called when an
instance is created, when an instance is re-initialized, when an instance is
updated to conform to a redefined class, and when an instance is updated to
conform to a different class. The generic function shared-initialize is called
by the system-supplied primary method for initialize-instance,
reinitialize-instance, update-instance-for-redefined-class, and
update-instance-for-different-class.
The generic function shared-initialize takes the following arguments: the
instance to be initialized, a specification of a set of names of slots
accessible in that instance, and any number of initialization arguments. The
arguments after the first two must form an initialization argument list. The
system-supplied primary method on shared-initialize initializes the slots with
values according to the initialization arguments and specified :initform forms.
The second argument indicates which slots should be initialized according to
their :initform forms if no initialization arguments are provided for those
slots.
The system-supplied primary method behaves as follows, regardless of whether
the slots are local or shared:
* If an initialization argument in the initialization argument list
specifies a value for that slot, that value is stored into the slot, even
if a value has already been stored in the slot before the method is run.
* Any slots indicated by the second argument that are still unbound at this
point are initialized according to their :initform forms. For any such
slot that has an :initform form, that form is evaluated in the lexical
environment of its defining defclass form and the result is stored into
the slot. For example, if a :before method stores a value in the slot, the
:initform form will not be used to supply a value for the slot.
* The rules mentioned in section 28.1.9.4 are obeyed.
The instance argument is the object to be initialized.
The slot-names argument specifies the slots that are to be initialized
according to their :initform forms if no initialization arguments apply. It is
supplied in one of three forms as follows:
* It can be a list of slot names, which specifies the set of those slot
names.
* It can be nil, which specifies the empty set of slot names.
* It can be the symbol t, which specifies the set of all of the slots.
The initargs argument consists of alternating initialization argument names and
values.
The modified instance is returned as the result.
Initialization arguments are declared valid by using the :initarg option to
defclass, or by defining methods for shared-initialize. The keyword name of
each keyword parameter specifier in the lambda-list of any method defined on
shared-initialize is declared a valid initialization argument name for all
classes for which that method is applicable.
Implementations are permitted to optimize :initform forms that neither produce
nor depend on side effects by evaluating these forms and storing them into
slots before running any initialize-instance methods, rather than by handling
them in the primary initialize-instance method. (This optimization might be
implemented by having the allocate-instance method copy a prototype instance.)
Implementations are permitted to optimize default initial value forms for
initialization arguments associated with slots by not actually creating the
complete initialization argument list when the only method that would receive
the complete list is the method on standard-object. In this case, default
initial value forms can be treated like :initform forms. This optimization has
no visible effects other than a performance improvement.
See sections 28.1.9, 28.1.9.4, 28.1.9.2 as well as initialize-instance,
reinitialize-instance, update-instance-for-redefined-class,
update-instance-for-different-class, slot-boundp, and slot-makunbound.
[Function]
slot-boundp instance slot-name
The function slot-boundp tests whether a specific slot in an instance is bound.
The arguments are the instance and the name of the slot.
The function slot-boundp returns true or false.
This function allows for writing :after methods on initialize-instance in order
to initialize only those slots that have not already been bound.
If no slot of the given name exists in the instance, slot-missing is called as
follows:
(slot-missing (class-of instance)
instance
slot-name
'slot-boundp)
The function slot-boundp is implemented using slot-boundp-using-class. See
slot-missing.
[Function]
slot-exists-p object slot-name
The function slot-exists-p tests whether the specified object has a slot of the
given name.
The object argument is any object. The slot-name argument is a symbol.
The function slot-exists-p returns true or false.
The function slot-exists-p is implemented using slot-exists-p-using-class.
[Function]
slot-makunbound instance slot-name
The function slot-makunbound restores a slot in an instance to the unbound
state.
The arguments to slot-makunbound are the instance and the name of the slot.
The instance is returned as the result.
If no slot of the given name exists in the instance, slot-missing is called as
follows:
(slot-missing (class-of instance)
instance
slot-name
'slot-makunbound)
The function slot-makunbound is implemented using slot-makunbound-using-class.
See slot-missing.
[Generic function]
slot-missing class object slot-name operation &optional new-value
[Primary method]
slot-missing (class t) object slot-name operation &optional new-value
The generic function slot-missing is invoked when an attempt is made to access
a slot in an object whose metaclass is standard-class and the name of the slot
provided is not a name of a slot in that class. The default method signals an
error.
The generic function slot-missing is not intended to be called by programmers.
Programmers may write methods for it.
The required arguments to slot-missing are the class of the object that is
being accessed, the object, the slot name, and a symbol that indicates the
operation that caused slot-missing to be invoked. The optional argument to
slot-missing is used when the operation is attempting to set the value of the
slot.
If a method written for slot-missing returns values, these values get returned
as the values of the original function invocation.
The generic function slot-missing may be called during evaluation of
slot-value, (setf slot-value), slot-boundp, and slot-makunbound. For each of
these operations the corresponding symbol for the operation argument is
slot-value, setf, slot-boundp, and slot-makunbound, respectively.
The set of arguments (including the class of the instance) facilitates defining
methods on the metaclass for slot-missing.
[Generic function]
slot-unbound class instance slot-name
[Primary method]
slot-unbound (class t) instance slot-name
The generic function slot-unbound is called when an unbound slot is read in an
instance whose metaclass is standard-class. The default method signals an
error.
The generic function slot-unbound is not intended to be called by programmers.
Programmers may write methods for it. The function slot-unbound is called only
by the function slot-value-using-class and thus indirectly by slot-value.
The arguments to slot-unbound are the class of the instance whose slot was
accessed, the instance itself, and the name of the slot.
If a method written for slot-unbound returns values, these values get returned
as the values of the original function invocation.
An unbound slot may occur if no :initform form was specified for the slot and
the slot value has not been set, or if slot-makunbound has been called on the
slot.
See slot-makunbound.
[Function]
slot-value object slot-name
The function slot-value returns the value contained in the slot slot-name of
the given object. If there is no slot with that name, slot-missing is called.
If the slot is unbound, slot-unbound is called.
The macro setf can be used with slot-value to change the value of a slot.
The arguments are the object and the name of the given slot.
The result is the value contained in the given slot.
If an attempt is made to read a slot and no slot of the given name exists in
the instance, slot-missing is called as follows:
(slot-missing (class-of instance)
instance
slot-name
'slot-value)
If an attempt is made to write a slot and no slot of the given name exists in
the instance, slot-missing is called as follows:
(slot-missing (class-of instance)
instance
slot-name
'setf
new-value)
The function slot-value is implemented using slot-value-using-class.
Implementations may optimize slot-value by compiling it in-line.
See slot-missing and slot-unbound.
[At this point the original CLOS report [5,7] contained a specification for
symbol-macrolet. This specification is omitted here. Instead, a description of
symbol-macrolet appears with those of related constructs in chapter 7.-GLS]
[Generic function]
update-instance-for-different-class previous current &rest initargs
[Primary method]
update-instance-for-different-class (previous standard-object)
(current standard-object) &rest initargs
The generic function update-instance-for-different-class is not intended to be
called by programmers. Programmers may write methods for it. This function is
called only by the function change-class.
The system-supplied primary method on update-instance-for-different-class
checks the validity of initialization arguments and signals an error if an
initialization argument is supplied that is not declared valid. This method
then initializes slots with values according to the initialization arguments
and initializes the newly added slots with values according to their :initform
forms. It does this by calling the generic function shared-initialize with the
following arguments: the instance, a list of names of the newly added slots,
and the initialization arguments it received. Newly added slots are those local
slots for which no slot of the same name exists in the previous class.
Methods for update-instance-for-different-class can be defined to specify
actions to be taken when an instance is updated. If only :after methods for
update-instance-for-different-class are defined, they will be run after the
system-supplied primary method for initialization and therefore will not
interfere with the default behavior of update-instance-for-different-class.
The arguments to update-instance-for-different-class are computed by
change-class. When change-class is invoked on an instance, a copy of that
instance is made; change-class then destructively alters the original instance.
The first argument to update-instance-for-different-class, previous, is that
copy; it holds the old slot values temporarily. This argument has dynamic
extent within change-class; if it is referenced in any way once
update-instance-for-different-class returns, the results are undefined. The
second argument to update-instance-for-different-class, current, is the altered
original instance.
The intended use of previous is to extract old slot values by using slot-value
or with-slots or by invoking a reader generic function, or to run other methods
that were applicable to instances of the original class.
The initargs argument consists of alternating initialization argument names and
values.
The value returned by update-instance-for-different-class is ignored by
change-class.
See the example for the function change-class.
Initialization arguments are declared valid by using the :initarg option to
defclass, or by defining methods for update-instance-for-different-class or
shared-initialize. The keyword name of each keyword parameter specifier in the
lambda-list of any method defined on update-instance-for-different-class or
shared-initialize is declared a valid initialization argument name for all
classes for which that method is applicable.
Methods on update-instance-for-different-class can be defined to initialize
slots differently from change-class. The default behavior of change-class is
described in section 28.1.11.
See sections 28.1.11, 28.1.9.4, and 28.1.9.2 as well as change-class and
shared-initialize.
[Generic function]
update-instance-for-redefined-class instance
added-slots discarded-slots property-list
&rest initargs
[Primary method]
update-instance-for-redefined-class (instance standard-object)
added-slots discarded-slots property-list
&rest initargs
The generic function update-instance-for-redefined-class is not intended to be
called by programmers. Programmers may write methods for it. The generic
function update-instance-for-redefined-class is called by the mechanism
activated by make-instances-obsolete.
The system-supplied primary method on update-instance-for-different-class
checks the validity of initialization arguments and signals an error if an
initialization argument is supplied that is not declared valid. This method
then initializes slots with values according to the initialization arguments
and initializes the newly added slots with values according to their :initform
forms. It does this by calling the generic function shared-initialize with the
following arguments: the instance, a list of names of the newly added slots,
and the initialization arguments it received. Newly added slots are those local
slots for which no slot of the same name exists in the old version of the
class.
When make-instances-obsolete is invoked or when a class has been redefined and
an instance is being updated, a property list is created that captures the slot
names and values of all the discarded slots with values in the original
instance. The structure of the instance is transformed so that it conforms to
the current class definition. The arguments to
update-instance-for-redefined-class are this transformed instance, a list of
the names of the new slots added to the instance, a list of the names of the
old slots discarded from the instance, and the property list containing the
slot names and values for slots that were discarded and had values. Included in
this list of discarded slots are slots that were local in the old class and are
shared in the new class.
The initargs argument consists of alternating initialization argument names and
values.
The value returned by update-instance-for-redefined-class is ignored.
Initialization arguments are declared valid by using the :initarg option to
defclass or by defining methods for update-instance-for-redefined-class or
shared-initialize. The keyword name of each keyword parameter specifier in the
lambda-list of any method defined on update-instance-for-redefined-class or
shared-initialize is declared a valid initialization argument name for all
classes for which that method is applicable.
See sections 28.1.10, 28.1.9.4, and 28.1.9.2 as well as shared-initialize and
make-instances-obsolete.
(defclass position () ())
(defclass x-y-position (position)
((x :initform 0 :accessor position-x)
(y :initform 0 :accessor position-y)))
;;; It turns out polar coordinates are used more than Cartesian
;;; coordinates, so the representation is altered and some new
;;; accessor methods are added.
(defmethod update-instance-for-redefined-class :before
((pos x-y-position) added deleted plist &key)
;; Transform the x-y coordinates to polar coordinates
;; and store into the new slots.
(let ((x (getf plist 'x))
(y (getf plist 'y)))
(setf (position-rho pos) (sqrt (+ (* x x) (* y y)))
(position-theta pos) (atan y x))))
(defclass x-y-position (position)
((rho :initform 0 :accessor position-rho)
(theta :initform 0 :accessor position-theta)))
;;; All instances of the old x-y-position class will be updated
;;; automatically.
;;; The new representation has the look and feel of the old one.
(defmethod position-x ((pos x-y-position))
(with-slots (rho theta) pos (* rho (cos theta))))
(defmethod (setf position-x) (new-x (pos x-y-position))
(with-slots (rho theta) pos
(let ((y (position-y pos)))
(setq rho (sqrt (+ (* new-x new-x) (* y y)))
theta (atan y new-x))
new-x)))
(defmethod position-y ((pos x-y-position))
(with-slots (rho theta) pos (* rho (sin theta))))
(defmethod (setf position-y) (new-y (pos x-y-position))
(with-slots (rho theta) pos
(let ((x (position-x pos)))
(setq rho (sqrt (+ (* x x) (* new-y new-y)))
theta (atan new-y x))
new-y)))
[Macro]
with-accessors ({slot-entry}*) instance-form
{declaration}* {form}*
The macro with-accessors creates a lexical environment in which specified slots
are lexically available through their accessors as if they were variables. The
macro with-accessors invokes the appropriate accessors to access the specified
slots. Both setf and setq can be used to set the value of the slot.
The result returned is that obtained by executing the forms specified by the
body argument.
Example:
(with-accessors ((x position-x) (y position-y)) p1
(setq x y))
A with-accessors expression of the form
(with-accessors ( ... ) instance
... )
... )
expands into the equivalent of
(let ((in instance))
(symbol-macrolet (( ( in))
...
( ( in)))
... )
... )
[X3J13 voted in March 1989 (SYMBOL-MACROLET-SEMANTICS) to modify the
definition of symbol-macrolet substantially and also voted
(SYMBOL-MACROLET-DECLARE) to allow declarations before the body of
symbol-macrolet but with peculiar treatment of special and type declarations.
The syntactic changes are reflected in this definition of with-accessors.-GLS]
See with-slots and symbol-macrolet.
[Special Form]
with-added-methods (function-name lambda-list
[[?option | {method-description}*]])
{form}*
The with-added-methods special form produces new generic functions and
establishes new lexical function definition bindings. Each generic function is
created by adding the set of methods specified by its method definitions to a
copy of the lexically visible generic function of the same name and its
methods. If such a generic function does not already exist, a new generic
function is created; this generic function has lexical scope.
The special form with-added-methods is used to define functions whose names are
meaningful only locally and to execute a series of forms with these function
definition bindings.
The names of functions defined by with-added-methods have lexical scope; they
retain their local definitions only within the body of the with-added-methods
construct. Any references within the body of the with-added-methods construct
to functions whose names are the same as those defined within the
with-added-methods form are thus references to the local functions instead of
to any global functions of the same names. The scope of these generic function
definition bindings includes the method bodies themselves as well as the body
of the with-added-methods construct.
The function-name, option, method-qualifier, and specialized-lambda-list
arguments are the same as for defgeneric.
The body of each method is enclosed in an implicit block. If function-name is a
symbol, this block bears the same name as the generic function. If
function-name is a list of the form (setf symbol), the name of the block is
symbol.
The result returned by with-added-methods is the value or values of the last
form executed. If no forms are specified, with-added-methods returns nil.
If a generic function with the given name already exists, the lambda-list
specified in the with-added-methods form must be congruent with the
lambda-lists of all existing methods on that function as well as with the
lambda-lists of all methods defined by the with-added-methods form; otherwise
an error is signaled.
If function-name specifies an existing generic function that has a different
value for any of the following option arguments, the copy of that generic
function is modified to have the new value: :argument-precedence-order,
declare, :documentation, :generic-function-class, :method-combination.
If function-name specifies an existing generic function that has a different
value for the :method-class option argument, that value is changed in the copy
of that generic function, but any methods copied from the existing generic
function are not changed.
If a function of the given name already exists, that function is copied into
the default method for a generic function of the given name. Note that this
behavior differs from that of defgeneric.
If a macro or special form of the given name already exists, an error is
signaled.
If there is no existing generic function, the option arguments have the same
default values as the option arguments to defgeneric.
See generic-labels, generic-flet, defmethod, defgeneric, and
ensure-generic-function.
[Macro]
with-slots ({slot-entry}*) instance-form
{declaration}* {form}*
slot-entry ::= slot-name | (variable-name slot-name)
The macro with-slots creates a lexical context for referring to specified slots
as though they were variables. Within such a context the value of the slot can
be specified by using its slot name, as if it were a lexically bound variable.
Both setf and setq can be used to set the value of the slot.
The macro with-slots translates an appearance of the slot name as a variable
into a call to slot-value.
The result returned is that obtained by executing the forms specified by the
body argument.
Example:
(with-slots (x y) position-1
(sqrt (+ (* x x) (* y y))))
(with-slots ((x1 x) (y1 y)) position-1
(with-slots ((x2 x) (y2 y)) position-2
(psetf x1 x2
y1 y2))))
(with-slots (x y) position
(setq x (1+ x)
y (1+ y)))
A with-slots expression of the form:
(with-slots ( ... ) instance
... )
... )
expands into the equivalent of
(let ((in instance))
(symbol-macrolet ( ... )
... )
... )
where is
( (slot-value in ' ))
if is a symbol and is
( (slot-value in ' ))
if is of the form ( ).
[X3J13 voted in March 1989 (SYMBOL-MACROLET-SEMANTICS) to modify the
definition of symbol-macrolet substantially and also voted
(SYMBOL-MACROLET-DECLARE) to allow declarations before the body of
symbol-macrolet but with peculiar treatment of special and type declarations.
The syntactic changes are reflected in this definition of with-slots.-GLS]
See with-accessors and symbol-macrolet.
[change_end]